/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using UnityEditor; using UnityEngine; internal class OVRConfigurationTask { internal static readonly string ConsoleLinkHref = "OpenOculusProjectSettings"; public Hash128 Uid { get; } public OVRProjectSetup.TaskGroup Group { get; } public BuildTargetGroup Platform { get; } public OptionalLambdaType Valid { get; } public OptionalLambdaType Level { get; } public OptionalLambdaType Message { get; } public OptionalLambdaType FixMessage { get; } public OptionalLambdaType URL { get; } public OVRConfigurationTaskSourceCode SourceCode { get; set; } private Func _isDone; public Func IsDone { get => GetDoneState; private set => _isDone = value; } public Action FixAction { get; } private readonly Dictionary _ignoreSettings = new Dictionary(); private readonly Dictionary _isDoneCache = new Dictionary(); public OVRConfigurationTask( OVRProjectSetup.TaskGroup group, BuildTargetGroup platform, Func isDone, Action fix, OptionalLambdaType level, OptionalLambdaType message, OptionalLambdaType fixMessage, OptionalLambdaType url, OptionalLambdaType valid) { Platform = platform; Group = group; IsDone = isDone; FixAction = fix; Level = level; Message = message; // If parameters are null, we're creating a OptionalLambdaType that points to default values // We don't want a null OptionalLambdaType, but we may be okay with an OptionalLambdaType containing a null value // For the URL for instance // Mandatory parameters will be checked on the Validate method down below URL = url ?? new OptionalLambdaTypeWithoutLambda(null); FixMessage = fixMessage ?? new OptionalLambdaTypeWithoutLambda(null); Valid = valid ?? new OptionalLambdaTypeWithoutLambda(true); // We may want to throw in case of some invalid parameters Validate(); var hash = new Hash128(); hash.Append(Message.Default); Uid = hash; SourceCode = new OVRConfigurationTaskSourceCode(this); } private void Validate() { if (Group == OVRProjectSetup.TaskGroup.All) { throw new ArgumentException( $"[{nameof(OVRConfigurationTask)}] {nameof(OVRProjectSetup.TaskGroup.All)} is not meant to be used as a {nameof(OVRProjectSetup.TaskGroup)} type"); } if (_isDone == null) { throw new ArgumentNullException(nameof(_isDone)); } if (Level == null) { throw new ArgumentNullException(nameof(Level)); } if (Message == null || !Message.Valid || string.IsNullOrEmpty(Message.Default)) { throw new ArgumentNullException(nameof(Message)); } } public void InvalidateCache(BuildTargetGroup buildTargetGroup) { Level.InvalidateCache(buildTargetGroup); Message.InvalidateCache(buildTargetGroup); URL.InvalidateCache(buildTargetGroup); Valid.InvalidateCache(buildTargetGroup); } public bool IsIgnored(BuildTargetGroup buildTargetGroup) { return GetIgnoreSetting(buildTargetGroup).Value; } public void SetIgnored(BuildTargetGroup buildTargetGroup, bool ignored) { GetIgnoreSetting(buildTargetGroup).Value = ignored; } public bool Fix(BuildTargetGroup buildTargetGroup) { try { FixAction(buildTargetGroup); } catch (OVRConfigurationTaskException exception) { Debug.LogWarning( $"[Oculus Settings] Failed to fix task \"{Message.GetValue(buildTargetGroup)}\" : {exception}"); } var hasChanged = UpdateAndGetStateChanged(buildTargetGroup); if (hasChanged) { var fixMessage = FixMessage.GetValue(buildTargetGroup); Debug.Log( fixMessage != null ? $"[Oculus Settings] Fixed task \"{Message.GetValue(buildTargetGroup)}\" : {fixMessage}" : $"[Oculus Settings] Fixed task \"{Message.GetValue(buildTargetGroup)}\""); } var isDone = IsDone(buildTargetGroup); OVRTelemetry.Start(OVRProjectSetupTelemetryEvent.EventTypes.Fix) .AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Uid, Uid.ToString()) .AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Level, Level.GetValue(buildTargetGroup).ToString()) .AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Group, Group.ToString()) .AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.BuildTargetGroup, buildTargetGroup.ToString()) .AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Value, isDone ? "true" : "false") .Send(); return isDone; } public string ComputeIgnoreUid(BuildTargetGroup buildTargetGroup) => $"{OVRProjectSetup.KeyPrefix}.{GetType().Name}.{Uid}.Ignored.{buildTargetGroup.ToString()}"; private OVRProjectSetupSettingBool GetIgnoreSetting(BuildTargetGroup buildTargetGroup) { if (!_ignoreSettings.TryGetValue(buildTargetGroup, out var item)) { var uid = ComputeIgnoreUid(buildTargetGroup); item = new OVRProjectSetupProjectSettingBool(uid, false); _ignoreSettings.Add(buildTargetGroup, item); } return item; } internal bool UpdateAndGetStateChanged(BuildTargetGroup buildTargetGroup) { var newState = _isDone(buildTargetGroup); var didStateChange = true; if (_isDoneCache.TryGetValue(buildTargetGroup, out var previousState)) { didStateChange = newState != previousState; } _isDoneCache[buildTargetGroup] = newState; return didStateChange; } internal void LogMessage(BuildTargetGroup buildTargetGroup) { var logMessage = GetFullLogMessage(buildTargetGroup); switch (Level.GetValue(buildTargetGroup)) { case OVRProjectSetup.TaskLevel.Optional: break; case OVRProjectSetup.TaskLevel.Recommended: Debug.LogWarning(logMessage); break; case OVRProjectSetup.TaskLevel.Required: if (OVRProjectSetup.RequiredThrowErrors.Value) { Debug.LogError(logMessage); } else { Debug.LogWarning(logMessage); } break; default: throw new ArgumentOutOfRangeException(); } } internal string GetFullLogMessage(BuildTargetGroup buildTargetGroup) { return $"{GetLogMessage(buildTargetGroup)}.\nYou can fix this by going to " + $"Edit > Project Settings > {OVRProjectSetupSettingsProvider.SettingsName}"; } internal string GetLogMessage(BuildTargetGroup buildTargetGroup) { return $"[{Group}] {Message.GetValue(buildTargetGroup)}"; } private bool GetDoneState(BuildTargetGroup buildTargetGroup) { if (_isDoneCache.TryGetValue(buildTargetGroup, out var cachedState)) { return cachedState; } return _isDone(buildTargetGroup); } #if UNITY_XR_CORE_UTILS internal Unity.XR.CoreUtils.Editor.BuildValidationRule ToValidationRule(BuildTargetGroup platform) { var validationRule = new Unity.XR.CoreUtils.Editor.BuildValidationRule { IsRuleEnabled = () => Valid.GetValue(platform), Category = Group.ToString(), Message = Message.GetValue(platform), CheckPredicate = () => IsDone(platform), FixIt = () => FixAction(platform), FixItAutomatic = true, FixItMessage = FixMessage.GetValue(platform), HelpText = null, HelpLink = null, SceneOnlyValidation = false, OnClick = null, Error = Level.GetValue(platform) == OVRProjectSetup.TaskLevel.Required }; return validationRule; } #endif }