Initialer Upload neues Unity-Projekt

This commit is contained in:
Daniel Ocks
2025-07-21 09:11:14 +02:00
commit eeca72985b
14558 changed files with 1508140 additions and 0 deletions

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 10ca0391ac84e854eb1b65f8c7f162bc
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,132 @@
fileFormatVersion: 2
guid: 23ed0d2bfc90b1d4f97cf416f2cd23a8
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,132 @@
fileFormatVersion: 2
guid: a5c6b8a6ed5d33749ac1f5783e1675f2
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,132 @@
fileFormatVersion: 2
guid: 0be6bd91c3ed459429f7e023ab85d7ee
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,132 @@
fileFormatVersion: 2
guid: f02eeecc6e9c02943ba538343bbe1a5b
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
mipmaps:
mipMapMode: 0
enableMipMap: 1
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 0
wrapV: 0
wrapW: 0
nPOTScale: 1
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Windows Store Apps
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@ -0,0 +1,135 @@
fileFormatVersion: 2
guid: daccb634c40170b40a52151fdcb6ea99
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 12
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
vTOnly: 0
ignoreMasterTextureLimit: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: 1
aniso: 1
mipBias: 0
wrapU: 1
wrapV: 1
wrapW: 0
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 0
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 2
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
cookieLightType: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 64
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Server
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Android
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID:
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
nameFileIdTable: {}
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,276 @@
/*
* 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.Collections.Generic;
using UnityEditor;
using System;
using System.Linq;
using UnityEngine;
/// <summary>
/// Core System for the OVRProjectSetup Tool
/// </summary>
/// <remarks>
/// This static class manages <see cref="OVRConfigurationTask"/> that can be added at any point.
/// Use the AddTask method to add and register <see cref="OVRConfigurationTask"/>.
/// </remarks>
public static class OVRProjectSetup
{
public enum TaskLevel
{
Optional = 0,
Recommended = 1,
Required = 2
}
public enum TaskGroup
{
All = 0,
Compatibility = 1,
Rendering = 2,
Quality = 3,
Physics = 4,
Packages = 5,
Features = 6,
Miscellaneous = 7
}
private static readonly OVRConfigurationTaskRegistry _principalRegistry;
internal static OVRConfigurationTaskRegistry Registry { get; private set; }
internal static OVRConfigurationTaskProcessorQueue ProcessorQueue { get; }
internal const string KeyPrefix = "OVRProjectSetup";
internal static OVRProjectSetupSettingBool Enabled;
internal static OVRProjectSetupSettingBool RequiredThrowErrors;
internal static readonly OVRProjectSetupSettingBool AllowLogs =
new OVRProjectSetupProjectSettingBool("AllowLogs", false, "Log outstanding issues");
internal static readonly OVRProjectSetupSettingBool ShowStatusIcon =
new OVRProjectSetupProjectSettingBool("ShowStatusIcon", true, "Show Status Icon");
internal static readonly OVRProjectSetupSettingBool ProduceReportOnBuild =
new OVRProjectSetupProjectSettingBool("ProduceReportOnBuild", false, "Produce Report on Build");
private static readonly HashSet<BuildTargetGroup> SupportedPlatforms = new HashSet<BuildTargetGroup>
{ BuildTargetGroup.Android, BuildTargetGroup.Standalone };
static OVRProjectSetup()
{
_principalRegistry = new OVRConfigurationTaskRegistry();
ProcessorQueue = new OVRConfigurationTaskProcessorQueue();
ConsoleLinkEventHandler.OnConsoleLink += OnConsoleLink;
RestoreRegistry();
ProcessorQueue.OnProcessorCompleted += RefreshBuildStatusMenuSubText;
var statusItem = new OVRStatusMenu.Item()
{
Name = "Project Setup Tool",
Color = OVREditorUtils.HexToColor("#4e4e4e"),
Icon = OVREditorUtils.CreateContent("ovr_icon_upst.png", OVRGUIContent.Source.ProjectSetupToolIcons),
InfoTextDelegate = GetMenuSubText,
OnClickDelegate = OnStatusMenuClick,
Order = 0
};
OVRStatusMenu.RegisterItem(statusItem);
}
private static string _statusMenuSubText;
private static void RefreshBuildStatusMenuSubText(OVRConfigurationTaskProcessor processor)
{
var updater = processor as OVRConfigurationTaskUpdater;
var summary = updater?.Summary;
_statusMenuSubText = summary?.ComputeNoticeMessage();
}
public static string GetMenuSubText() => _statusMenuSubText;
private static void OnStatusMenuClick()
{
OVRProjectSetupSettingsProvider.OpenSettingsWindow(OVRProjectSetupSettingsProvider.Origins.Icon);
}
internal static void SetupTemporaryRegistry()
{
Registry = new OVRConfigurationTaskRegistry();
Enabled = new OVRProjectSetupConstSettingBool("Enabled", true, "Enabled");
RequiredThrowErrors =
new OVRProjectSetupConstSettingBool("RequiredThrowErrors", false, "Required throw errors");
OVRProjectSetupUpdater.SetupTemporaryRegistry();
}
internal static void RestoreRegistry()
{
Registry = _principalRegistry;
Enabled =
new OVRProjectSetupConstSettingBool("Enabled", true, "Enabled");
RequiredThrowErrors =
new OVRProjectSetupProjectSettingBool("RequiredThrowErrors", false, "Required throw errors");
OVRProjectSetupUpdater.RestoreRegistry();
}
private static void OnConsoleLink(Dictionary<string, string> infos)
{
if (infos.TryGetValue("href", out var href))
{
if (href == OVRConfigurationTask.ConsoleLinkHref)
{
OVRProjectSetupSettingsProvider.OpenSettingsWindow(OVRProjectSetupSettingsProvider.Origins.Console);
}
}
}
internal static IEnumerable<OVRConfigurationTask> GetTasks(BuildTargetGroup buildTargetGroup, bool refresh)
{
return Registry.GetTasks(buildTargetGroup, refresh);
}
/// <summary>
/// Add an <see cref="OVRConfigurationTask"/> to the Setup Tool.
/// </summary>
/// <remarks>
/// This methods adds and registers an already created <see cref="OVRConfigurationTask"/> to the SetupTool.
/// We recommend the use of the other AddTask method with all the required parameters to create the task.
/// </remarks>
/// <param name="task">The task that will get registered to the Setup Tool.</param>
/// <exception cref="ArgumentException">Possible causes :
/// - a task with the same unique ID already has been registered (conflict in hash generated from description message).</exception>
internal static void AddTask(OVRConfigurationTask task)
{
Registry.AddTask(task);
}
/// <summary>
/// Add an <see cref="OVRConfigurationTask"/> to the Setup Tool.
/// </summary>
/// <remarks>
/// This methods creates, adds and registers an <see cref="OVRConfigurationTask"/> to the SetupTool.
/// Please note that the Message or ConditionalMessage parameters have to be unique since they are being hashed to generate a Unique ID for the task.
/// Those tasks, once added, are not meant to be removed from the Setup Tool, and will get checked at some key points.
/// This method is the one entry point for developers to add their own sanity checks, technical requirements or other recommendations.
/// You can use the conditional parameters that accepts lambdas or delegates for more complex behaviours if needed.
/// </remarks>
/// <param name="group">Category that fits the task. Feel free to add more to the enum if relevant. Do not use "All".</param>
/// <param name="isDone">Delegate that checks if the Configuration Task is validated or not.</param>
/// <param name="platform">Platform for which this Configuration Task applies. Use "Unknown" for any.</param>
/// <param name="fix">Delegate that validates the Configuration Task.</param>
/// <param name="level">Severity (or behaviour) of the Configuration Task.</param>
/// <param name="conditionalLevel">Use this delegate for more control or complex behaviours over the level parameter.</param>
/// <param name="message">Description of the Configuration Task.</param>
/// <param name="conditionalMessage">Use this delegate for more control or complex behaviours over the message parameter.</param>
/// <param name="fixMessage">Description of the actual fix for the Task.</param>
/// <param name="conditionalFixMessage">Use this delegate for more control or complex behaviours over the fixMessage parameter.</param>
/// <param name="url">Url to more information about the Configuration Task.</param>
/// <param name="conditionalUrl">Use this delegate for more control or complex behaviours over the url parameter.</param>
/// <param name="validity">Checks if the task is valid. If not, it will be ignored by the Setup Tool.</param>
/// <param name="conditionalValidity">Use this delegate for more control or complex behaviours over the validity parameter.</param>
/// <exception cref="ArgumentNullException">Possible causes :
/// - If either message or conditionalMessage do not provide a valid non null string
/// - isDone is null
/// - fix is null</exception>
/// <exception cref="ArgumentException">Possible causes :
/// - group is set to "All". This category is not meant to be used to describe a task.
/// - a task with the same unique ID already has been registered (conflict in hash generated from description message).</exception>
public static void AddTask(
OVRProjectSetup.TaskGroup group,
Func<BuildTargetGroup, bool> isDone,
BuildTargetGroup platform = BuildTargetGroup.Unknown,
Action<BuildTargetGroup> fix = null,
OVRProjectSetup.TaskLevel level = OVRProjectSetup.TaskLevel.Recommended,
Func<BuildTargetGroup, OVRProjectSetup.TaskLevel> conditionalLevel = null,
string message = null,
Func<BuildTargetGroup, string> conditionalMessage = null,
string fixMessage = null,
Func<BuildTargetGroup, string> conditionalFixMessage = null,
string url = null,
Func<BuildTargetGroup, string> conditionalUrl = null,
bool validity = true,
Func<BuildTargetGroup, bool> conditionalValidity = null
)
{
var optionalLevel =
OptionalLambdaType<BuildTargetGroup, OVRProjectSetup.TaskLevel>.Create(level, conditionalLevel, true);
var optionalMessage = OptionalLambdaType<BuildTargetGroup, string>.Create(message, conditionalMessage, true);
var optionalFixMessage =
OptionalLambdaType<BuildTargetGroup, string>.Create(fixMessage, conditionalFixMessage, true);
var optionalUrl = OptionalLambdaType<BuildTargetGroup, string>.Create(url, conditionalUrl, true);
var optionalValidity = OptionalLambdaType<BuildTargetGroup, bool>.Create(validity, conditionalValidity, true);
AddTask(new OVRConfigurationTask(group, platform, isDone, fix, optionalLevel, optionalMessage,
optionalFixMessage, optionalUrl, optionalValidity));
}
internal static bool IsPlatformSupported(BuildTargetGroup buildTargetGroup)
{
return SupportedPlatforms.Contains(buildTargetGroup);
}
internal enum LogMessages
{
Disabled = 0,
Summary = 1,
Changed = 2,
All = 3,
}
private const int LoopExitCount = 4;
internal static void FixTasks(
BuildTargetGroup buildTargetGroup,
Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> filter = null,
LogMessages logMessages = LogMessages.Disabled,
bool blocking = true,
Action<OVRConfigurationTaskProcessor> onCompleted = null)
{
var fixer = new OVRConfigurationTaskFixer(Registry, buildTargetGroup, filter, logMessages, blocking,
onCompleted);
ProcessorQueue.Request(fixer);
}
internal static void FixTask(
BuildTargetGroup buildTargetGroup,
OVRConfigurationTask task,
LogMessages logMessages = LogMessages.Disabled,
bool blocking = true,
Action<OVRConfigurationTaskProcessor> onCompleted = null
)
{
// TODO : A bit overkill for just one task
var filter = (Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>>)(tasks =>
tasks.Where(otherTask => otherTask == task).ToList());
var fixer = new OVRConfigurationTaskFixer(Registry, buildTargetGroup, filter, logMessages, blocking,
onCompleted);
ProcessorQueue.Request(fixer);
}
internal static void UpdateTasks(
BuildTargetGroup buildTargetGroup,
Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> filter = null,
LogMessages logMessages = LogMessages.Disabled,
bool blocking = true,
Action<OVRConfigurationTaskProcessor> onCompleted = null)
{
var updater =
new OVRConfigurationTaskUpdater(Registry, buildTargetGroup, filter, logMessages, blocking, onCompleted);
ProcessorQueue.Request(updater);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 65fb7bdd13ad2744ebc0000885584ce6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,89 @@
/*
* 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.IO;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
internal class OVRProjectSetupBuildValidator : IPreprocessBuildWithReport
{
public int callbackOrder => 0;
public void OnPreprocessBuild(BuildReport report)
{
var outputDirectory = Path.GetDirectoryName(report.summary.outputPath);
PreprocessBuild(report.summary.platformGroup, outputDirectory);
}
public static void PreprocessBuild(BuildTargetGroup buildTargetGroup, string reportOutputPath = null)
{
if (!OVRProjectSetup.IsPlatformSupported(buildTargetGroup))
{
return;
}
OVRProjectSetup.UpdateTasks(buildTargetGroup, onCompleted: OnUpdated(reportOutputPath));
foreach (var task in OVRProjectSetup.GetTasks(buildTargetGroup, false))
{
ValidateTask(task, buildTargetGroup);
}
}
private static Action<OVRConfigurationTaskProcessor> OnUpdated(string outputPath)
{
return (processor) =>
{
if (!OVRProjectSetup.ProduceReportOnBuild.Value) return;
var updater = processor as OVRConfigurationTaskUpdater;
try
{
updater?.Summary?.GenerateReport(outputPath);
}
catch (Exception e)
{
Debug.LogWarning(e.Message);
}
};
}
private static void ValidateTask(OVRConfigurationTask task, BuildTargetGroup buildTargetGroup)
{
if (task.IsIgnored(buildTargetGroup)
|| task.Level.GetValue(buildTargetGroup) != OVRProjectSetup.TaskLevel.Required
|| task.IsDone(buildTargetGroup))
{
return;
}
if (OVRProjectSetup.RequiredThrowErrors.Value)
{
throw new BuildFailedException(task.GetFullLogMessage(buildTargetGroup));
}
else
{
Debug.LogWarning(task.GetFullLogMessage(buildTargetGroup));
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ef3b0673029bea046ba4346b5fbbe59e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,69 @@
/*
* 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.IO;
using UnityEditor;
/// <summary>
/// Static class for the OVRProjectSetup Tool that contains methods intended to be called from the CLI
/// </summary>
public class OVRProjectSetupCLI
{
/// <summary>
/// Generate a project setup report and write it to a file.
/// </summary>
/// <remarks>
/// This generates a project setup report for the active platform build target and write it to a file.
/// The active platform build target may be specified using the "-buildTarget" CLI argument.
/// The output file can be specified using the "-reportFile" CLI argument. If not specified, a
/// file with a generated name will be created in the current folder.
/// </remarks>
public static void GenerateProjectSetupReport()
{
var buildTarget = EditorUserBuildSettings.activeBuildTarget;
var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(buildTarget);
var reportFile = GetArgValue("-reportFile");
var outputFolder = reportFile != null ? Path.GetDirectoryName(reportFile) : "./";
var outputFile = Path.GetFileName(reportFile);
OVRProjectSetup.UpdateTasks(buildTargetGroup, logMessages: OVRProjectSetup.LogMessages.Disabled, blocking: true,
onCompleted: processor =>
{
var updater = processor as OVRConfigurationTaskUpdater;
updater?.Summary.GenerateReport(outputFolder, outputFile);
});
}
private static string GetArgValue(string argName)
{
var args = System.Environment.GetCommandLineArgs();
for (var i = 0; i < args.Length; i++)
{
if (args[i] == argName)
{
return args[i + 1];
}
}
return null;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: de9f8b9e7f4f94a7ebb0b090513870ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,728 @@
/*
* 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 System.Linq;
using UnityEditor;
using UnityEngine;
internal class OVRProjectSetupDrawer
{
private class Styles
{
private const float SmallIconSize = 16.0f;
private const float FixButtonWidth = 64.0f;
private const float FixAllButtonWidth = 80.0f;
internal const float GroupSelectionWidth = 244.0f;
internal const float LabelWidth = 96f;
internal const float TitleLabelWidth = 196f;
internal readonly GUIStyle Wrap = new GUIStyle(EditorStyles.label)
{
wordWrap = true,
alignment = TextAnchor.MiddleLeft,
padding = new RectOffset(0, 5, 1, 1)
};
internal readonly GUIStyle IssuesBackground = new GUIStyle("ScrollViewAlt")
{
};
internal readonly GUIStyle ListLabel = new GUIStyle("TV Selection")
{
border = new RectOffset(0, 0, 0, 0),
padding = new RectOffset(5, 5, 5, 3),
margin = new RectOffset(4, 4, 4, 5)
};
internal readonly GUIStyle IssuesTitleLabel = new GUIStyle(EditorStyles.label)
{
fontSize = 14,
wordWrap = false,
stretchWidth = false,
fontStyle = FontStyle.Bold,
padding = new RectOffset(10, 10, 0, 0)
};
internal readonly GUIStyle GenerateReportButton = new GUIStyle(EditorStyles.miniButton)
{
margin = new RectOffset(0, 10, 2, 2),
stretchWidth = false,
};
internal readonly GUIStyle FixButton = new GUIStyle(EditorStyles.miniButton)
{
margin = new RectOffset(0, 10, 2, 2),
stretchWidth = false,
fixedWidth = FixButtonWidth,
};
internal readonly GUIStyle FixAllButton = new GUIStyle(EditorStyles.miniButton)
{
margin = new RectOffset(0, 10, 2, 2),
stretchWidth = false,
fixedWidth = FixAllButtonWidth,
};
internal readonly GUIStyle InlinedIconStyle = new GUIStyle(EditorStyles.label)
{
margin = new RectOffset(0, 0, 0, 0),
padding = new RectOffset(0, 0, 0, 0),
fixedWidth = SmallIconSize,
fixedHeight = SmallIconSize
};
internal readonly GUIStyle IconStyle = new GUIStyle(EditorStyles.label)
{
margin = new RectOffset(5, 5, 4, 5),
padding = new RectOffset(0, 0, 0, 0),
fixedWidth = SmallIconSize,
fixedHeight = SmallIconSize
};
internal readonly GUIStyle SubtitleHelpText = new GUIStyle(EditorStyles.miniLabel)
{
margin = new RectOffset(10, 0, 0, 0),
wordWrap = true
};
internal readonly GUIStyle InternalHelpBox = new GUIStyle(EditorStyles.helpBox)
{
margin = new RectOffset(5, 5, 5, 5)
};
internal readonly GUIStyle InternalHelpText = new GUIStyle(EditorStyles.miniLabel)
{
margin = new RectOffset(10, 0, 0, 0),
wordWrap = true,
fontStyle = FontStyle.Italic,
normal =
{
textColor = new Color(0.58f, 0.72f, 0.95f)
}
};
internal readonly GUIStyle NormalStyle = new GUIStyle(EditorStyles.label)
{
margin = new RectOffset(10, 0, 0, 0),
wordWrap = true,
stretchWidth = false
};
internal readonly GUIStyle BoldStyle = new GUIStyle(EditorStyles.label)
{
margin = new RectOffset(10, 0, 0, 0),
stretchWidth = false,
wordWrap = true,
fontStyle = FontStyle.Bold
};
internal readonly GUIStyle MiniButton = new GUIStyle(EditorStyles.miniButton)
{
clipping = TextClipping.Overflow,
fixedHeight = 18.0f,
fixedWidth = 18.0f,
margin = new RectOffset(2, 2, 2, 2),
padding = new RectOffset(1, 1, 1, 1)
};
internal readonly GUIStyle Foldout = new GUIStyle(EditorStyles.foldoutHeader)
{
margin = new RectOffset(0, 0, 0, 0),
padding = new RectOffset(16, 5, 5, 5),
fixedHeight = 26.0f
};
internal readonly GUIStyle FoldoutHorizontal = new GUIStyle(EditorStyles.label)
{
fixedHeight = 26.0f
};
internal readonly GUIStyle List = new GUIStyle(EditorStyles.helpBox)
{
margin = new RectOffset(3, 3, 3, 3),
padding = new RectOffset(3, 3, 3, 3)
};
}
private static Styles _styles;
private static Styles styles => _styles ??= new Styles();
private readonly OVRProjectSetupSettingBool _showOutstandingItems =
new OVRProjectSetupUserSettingBool("ShowOutstandingItems", true);
private readonly OVRProjectSetupSettingBool _showRecommendedItems =
new OVRProjectSetupUserSettingBool("ShowRecommendedItems", true);
private readonly OVRProjectSetupSettingBool _showVerifiedItems =
new OVRProjectSetupUserSettingBool("ShowVerifiedItems", false);
private readonly OVRProjectSetupSettingBool _showIgnoredItems =
new OVRProjectSetupUserSettingBool("ShowIgnoredItems", false);
private static readonly GUIContent Title = new GUIContent("Project Setup Tool");
private static readonly GUIContent Description =
new GUIContent("This tool maintains a checklist of required setup tasks as well as best practices to " +
"ensure your project is ready to go. Follow our suggestions and fixes to quickly setup your project.");
private static readonly GUIContent SummaryLabel = new GUIContent("Current project status: ");
private static readonly GUIContent ListTitle = new GUIContent("Checklist");
private static readonly GUIContent UnsupportedTitle = new GUIContent("Unsupported Platform");
private static readonly GUIContent Filter =
new GUIContent("Filter by Group :", "Filters the task to the selected group.");
private static readonly GUIContent FixButtonContent = new GUIContent("Fix", "Fix with recommended settings");
private static readonly GUIContent FixAllButtonContent =
new GUIContent("Fix All", "Fix all the issues from this category");
private static readonly GUIContent ApplyButtonContent = new GUIContent("Apply", "Apply the recommended settings");
private static readonly GUIContent ApplyAllButtonContent =
new GUIContent("Apply All", "Apply the recommended settings for all the items in this category");
private static readonly GUIContent RefreshTasksButtonContent =
new GUIContent("Refresh", "Refresh the items in the list");
private static readonly GUIContent GenerateReportButtonContent =
new GUIContent("Generate report", "Generate a report of all the issues");
private static readonly OVRGUIContent WarningIcon = OVREditorUtils.CreateContent("ovr_icon_category_warning.png", OVRGUIContent.Source.ProjectSetupToolIcons);
private static readonly OVRGUIContent ErrorIcon = OVREditorUtils.CreateContent("ovr_icon_category_error.png", OVRGUIContent.Source.ProjectSetupToolIcons);
private static readonly OVRGUIContent InfoIcon = OVREditorUtils.CreateContent("ovr_icon_category_neutral.png", OVRGUIContent.Source.ProjectSetupToolIcons);
private static readonly OVRGUIContent TestPassedIcon =
OVREditorUtils.CreateContent("ovr_icon_category_success.png", OVRGUIContent.Source.ProjectSetupToolIcons);
private static readonly OVRGUIContent ConfigIcon =
OVREditorUtils.CreateContent("_Popup", OVRGUIContent.Source.BuiltIn, "Additional options");
private static readonly OVRGUIContent DocumentationIcon =
OVREditorUtils.CreateContent("ovr_icon_documentation.png", OVRGUIContent.Source.GenericIcons, "Go to Documentation");
private const string OutstandingItems = "Outstanding Issues";
private const string RecommendedItems = "Recommended Items";
private const string VerifiedItems = "Verified Items";
private const string IgnoredItems = "Ignored Items";
private const string OutFolderTitle = "Select output folder";
private const string ErrorTitle = "Error";
private const string SuccessTitle = "Success";
private const string ReportGenerationErrorMessage = "Could not generate the project setup report.";
private const string ReportGenerationSuccessMessage = "Project setup report generated successfully at:";
private const string TasksRefreshErrorMessage = "Could not refresh the checklist.";
private const string TasksRefreshSuccessMessage = "Tasks refreshed successfully.";
private const string OkButton = "ok";
private const string DocumentationUrl =
"https://developer.oculus.com/documentation/unity/unity-upst-overview";
// Internals
private OVRProjectSetup.TaskGroup _selectedTaskGroup;
private BuildTargetGroup _selectedBuildTargetGroup = BuildTargetGroup.Unknown;
private Vector2 _scrollViewPos = Vector2.zero;
private OVRConfigurationTaskUpdaterSummary _lastSummary;
internal OVRProjectSetupDrawer()
{
_selectedTaskGroup = OVRProjectSetup.TaskGroup.All;
}
private class BuildTargetSelectionScope : GUI.Scope
{
public BuildTargetGroup BuildTargetGroup { get; protected set; }
public BuildTargetSelectionScope()
{
BuildTargetGroup = EditorGUILayout.BeginBuildTargetSelectionGrouping();
if (BuildTargetGroup == BuildTargetGroup.Unknown)
{
BuildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
}
}
protected override void CloseScope() => EditorGUILayout.EndVertical();
}
private TEnumType EnumPopup<TEnumType>(GUIContent content, TEnumType currentValue, Action<TEnumType> onChanged)
where TEnumType : Enum, IComparable
{
var previousLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = Styles.LabelWidth;
TEnumType newValue =
(TEnumType)EditorGUILayout.EnumPopup(content, currentValue, GUILayout.Width(Styles.GroupSelectionWidth));
EditorGUIUtility.labelWidth = previousLabelWidth;
if (!newValue.Equals(currentValue))
{
onChanged(newValue);
}
return newValue;
}
private bool FoldoutWithAdditionalAction(OVRProjectSetupSettingBool key, string label, Rect rect,
Action inlineAdditionalAction)
{
var previousLabelWidth = EditorGUIUtility.labelWidth;
EditorGUIUtility.labelWidth = rect.width - 8;
bool foldout;
using (new EditorGUILayout.HorizontalScope(styles.FoldoutHorizontal))
{
foldout = Foldout(key, label);
inlineAdditionalAction?.Invoke();
}
EditorGUIUtility.labelWidth = previousLabelWidth;
return foldout;
}
private bool Foldout(OVRProjectSetupSettingBool key, string label)
{
var currentValue = key.Value;
var newValue = EditorGUILayout.Foldout(currentValue, label, true, styles.Foldout);
if (newValue != currentValue)
{
key.Value = newValue;
}
return newValue;
}
private OVRGUIContent GetTaskIcon(OVRConfigurationTask task, BuildTargetGroup buildTargetGroup)
{
if (task.IsDone(buildTargetGroup))
{
return TestPassedIcon;
}
return task.Level.GetValue(buildTargetGroup) switch
{
OVRProjectSetup.TaskLevel.Required => ErrorIcon,
OVRProjectSetup.TaskLevel.Recommended => WarningIcon,
OVRProjectSetup.TaskLevel.Optional => InfoIcon,
_ => throw new ArgumentOutOfRangeException()
};
}
private string GenerateReport(BuildTargetGroup buildTargetGroup, string outputPath)
{
if (_lastSummary == null)
{
OVRProjectSetup.UpdateTasks(buildTargetGroup, logMessages: OVRProjectSetup.LogMessages.Disabled,
blocking: true, onCompleted: processor =>
{
var updater = processor as OVRConfigurationTaskUpdater;
_lastSummary = updater?.Summary;
});
return _lastSummary?.GenerateReport(outputPath);
}
return _lastSummary.GenerateReport(outputPath);
}
private void UpdateTasks(BuildTargetGroup buildTargetGroup)
{
OVRProjectSetup.UpdateTasks(buildTargetGroup, logMessages: OVRProjectSetup.LogMessages.Disabled,
blocking: false, onCompleted: OnUpdated);
}
private void OnUpdated(OVRConfigurationTaskProcessor processor)
{
var updater = processor as OVRConfigurationTaskUpdater;
_lastSummary = updater?.Summary;
}
private void ShowSettingsMenu()
{
var menu = new GenericMenu();
OVRProjectSetup.Enabled.AppendToMenu(menu);
OVRProjectSetupUpdater.Enabled.AppendToMenu(menu);
OVRProjectSetup.RequiredThrowErrors.AppendToMenu(menu);
OVRProjectSetup.AllowLogs.AppendToMenu(menu);
OVRProjectSetup.ShowStatusIcon.AppendToMenu(menu);
OVRProjectSetup.ProduceReportOnBuild.AppendToMenu(menu);
menu.ShowAsContext();
}
private void ShowItemMenu(BuildTargetGroup buildTargetGroup, OVRConfigurationTask task)
{
var menu = new GenericMenu();
var hasDocumentation = !string.IsNullOrEmpty(task.URL.GetValue(buildTargetGroup));
if (hasDocumentation)
{
menu.AddItem(new GUIContent("Documentation"), false, OnDocumentation,
new object[] { buildTargetGroup, task });
}
var hasSourceCode = task.SourceCode.Valid;
if (hasSourceCode)
{
menu.AddItem(new GUIContent("Go to Source Code"), false, OnGoToSourceCode,
new object[] { buildTargetGroup, task });
}
menu.AddItem(new GUIContent("Ignore"), task.IsIgnored(buildTargetGroup), OnIgnore,
new object[] { buildTargetGroup, task });
menu.ShowAsContext();
}
internal void OnTitleBarGUI()
{
if (GUILayout.Button(ConfigIcon, styles.MiniButton))
{
ShowSettingsMenu();
}
if (GUILayout.Button(DocumentationIcon, styles.MiniButton))
{
Application.OpenURL(DocumentationUrl);
}
}
internal void OnGUI()
{
// Title
GUILayout.Label(Title, styles.IssuesTitleLabel);
// Short Description
GUILayout.Label(Description, styles.SubtitleHelpText);
EditorGUILayout.Space();
var enabled = OVRProjectSetup.Enabled.Value;
using (new EditorGUI.DisabledScope(!enabled))
{
// Summary
using (new EditorGUILayout.HorizontalScope())
{
GUILayout.Label(SummaryLabel, styles.NormalStyle);
if (enabled)
{
GUILayout.Label(OVRProjectSetupStatusIcon.ComputeIcon(_lastSummary), styles.InlinedIconStyle);
GUILayout.Label(_lastSummary?.ComputeNoticeMessage() ?? "", styles.BoldStyle);
}
else
{
GUILayout.Label("Setup Tool is disabled", styles.BoldStyle);
}
}
// Checklist
using (var buildTargetSelection = new BuildTargetSelectionScope())
{
var buildTargetGroup = buildTargetSelection.BuildTargetGroup;
if (_selectedBuildTargetGroup != buildTargetGroup)
{
_selectedBuildTargetGroup = buildTargetGroup;
UpdateTasks(buildTargetGroup);
}
using (new EditorGUILayout.VerticalScope())
{
EditorGUILayout.Space();
DrawTasksList(_selectedBuildTargetGroup);
}
}
}
}
private void DrawTasksList(BuildTargetGroup buildTargetGroup)
{
var disableTasksList = EditorApplication.isPlaying;
using (new EditorGUI.DisabledGroupScope(disableTasksList))
{
// Header
using (new EditorGUILayout.HorizontalScope())
{
// Title
GUILayout.Label(ListTitle,
styles.IssuesTitleLabel, GUILayout.Width(Styles.TitleLabelWidth));
GUILayout.FlexibleSpace();
// Filter
EnumPopup<OVRProjectSetup.TaskGroup>(Filter, _selectedTaskGroup,
group => _selectedTaskGroup = group);
// More Actions Menu Button
DrawMoreActionsMenuList(buildTargetGroup);
}
// Scroll View
_scrollViewPos = EditorGUILayout.BeginScrollView(_scrollViewPos, styles.IssuesBackground,
GUILayout.ExpandHeight(true));
DrawCategory(_showOutstandingItems, tasks => tasks
.Where(task =>
(_selectedTaskGroup == OVRProjectSetup.TaskGroup.All || task.Group == _selectedTaskGroup)
&& !task.IsDone(buildTargetGroup)
&& !task.IsIgnored(buildTargetGroup)
&& (task.Level.GetValue(buildTargetGroup) == OVRProjectSetup.TaskLevel.Required))
.OrderByDescending(task => task.FixAction == null)
.ToList(),
buildTargetGroup, OutstandingItems, true);
DrawCategory(_showRecommendedItems, tasks => tasks
.Where(task =>
(_selectedTaskGroup == OVRProjectSetup.TaskGroup.All || task.Group == _selectedTaskGroup)
&& !task.IsDone(buildTargetGroup)
&& !task.IsIgnored(buildTargetGroup)
&& (task.Level.GetValue(buildTargetGroup) != OVRProjectSetup.TaskLevel.Required))
.OrderByDescending(task => task.Level.GetValue(buildTargetGroup))
.ThenBy(task => task.FixAction == null)
.ToList(),
buildTargetGroup, RecommendedItems, true);
DrawCategory(_showVerifiedItems, tasks => tasks
.Where(task =>
(_selectedTaskGroup == OVRProjectSetup.TaskGroup.All || task.Group == _selectedTaskGroup)
&& task.IsDone(buildTargetGroup)
&& !task.IsIgnored(buildTargetGroup))
.OrderByDescending(task => task.FixAction == null)
.ThenBy(task => task.Level.GetValue(buildTargetGroup))
.ToList(),
buildTargetGroup, VerifiedItems, false);
DrawCategory(_showIgnoredItems, tasks => tasks
.Where(task =>
(_selectedTaskGroup == OVRProjectSetup.TaskGroup.All || task.Group == _selectedTaskGroup)
&& task.IsIgnored(buildTargetGroup))
.OrderByDescending(task => task.Level.GetValue(buildTargetGroup))
.ThenBy(task => task.FixAction != null)
.ToList(),
buildTargetGroup, IgnoredItems, false);
EditorGUILayout.EndScrollView();
}
}
private void DrawCategory(OVRProjectSetupSettingBool key, Func<IEnumerable<OVRConfigurationTask>,
List<OVRConfigurationTask>> filter, BuildTargetGroup buildTargetGroup, string title, bool fixAllButton)
{
var tasks = filter(OVRProjectSetup.GetTasks(buildTargetGroup, false));
if (key == null || tasks == null || tasks.Count == 0)
{
return;
}
using (var scope = new EditorGUILayout.VerticalScope(styles.List))
{
var rect = scope.rect;
// Foldout
title = $"{title} ({tasks.Count})";
var foldout = FoldoutWithAdditionalAction(key, title, rect, () =>
{
if (fixAllButton)
{
if (tasks.Any(task => task.FixAction != null))
{
var content = tasks[0].Level.GetValue(buildTargetGroup) == OVRProjectSetup.TaskLevel.Required
? FixAllButtonContent
: ApplyAllButtonContent;
EditorGUI.BeginDisabledGroup(
OVRProjectSetup.ProcessorQueue.BusyWith(OVRConfigurationTaskProcessor.ProcessorType.Fixer));
if (GUILayout.Button(content, styles.FixAllButton))
{
OVRProjectSetupSettingsProvider.SetNewInteraction(OVRProjectSetupSettingsProvider
.Interaction.Fixed);
OVRProjectSetup.FixTasks(buildTargetGroup, filter, blocking: false,
onCompleted: AfterFixApply);
}
EditorGUI.EndDisabledGroup();
}
}
});
if (foldout)
{
DrawIssues(tasks, buildTargetGroup);
}
}
}
private void AfterFixApply(OVRConfigurationTaskProcessor processor)
{
AssetDatabase.SaveAssets();
UpdateTasks(processor.BuildTargetGroup);
}
private void DrawIssues(List<OVRConfigurationTask> tasks, BuildTargetGroup buildTargetGroup)
{
foreach (var task in tasks)
{
DrawIssue(task, buildTargetGroup);
}
}
private void DrawIssue(OVRConfigurationTask task, BuildTargetGroup buildTargetGroup)
{
var ignored = task.IsIgnored(buildTargetGroup);
var cannotBeFixed = task.IsDone(buildTargetGroup) ||
OVRProjectSetup.ProcessorQueue.BusyWith(OVRConfigurationTaskProcessor.ProcessorType.Fixer);
var disabled = cannotBeFixed || ignored;
// Note : We're not using scopes, because in this very case, we've got a cross of scopes
EditorGUI.BeginDisabledGroup(disabled);
var clickArea = EditorGUILayout.BeginHorizontal(styles.ListLabel);
// Icon
GUILayout.Label(GetTaskIcon(task, buildTargetGroup), styles.IconStyle);
// Message
GUILayout.Label(new GUIContent(task.Message.GetValue(buildTargetGroup)), styles.Wrap);
EditorGUI.EndDisabledGroup();
if (task.FixAction != null)
{
EditorGUI.BeginDisabledGroup(cannotBeFixed);
var content = task.Level.GetValue(buildTargetGroup) == OVRProjectSetup.TaskLevel.Required
? FixButtonContent
: ApplyButtonContent;
var fixMessage = task.FixMessage.GetValue(buildTargetGroup);
var tooltip = fixMessage != null ? $"{content.tooltip} :\n{fixMessage}" : content.tooltip;
content = new GUIContent(content.text, tooltip);
if (GUILayout.Button(content, styles.FixButton))
{
OVRProjectSetupSettingsProvider.SetNewInteraction(OVRProjectSetupSettingsProvider.Interaction.Fixed);
OVRProjectSetup.FixTask(buildTargetGroup, task, blocking: false, onCompleted: AfterFixApply);
}
EditorGUI.EndDisabledGroup();
}
var current = Event.current;
if (GUILayout.Button("", EditorStyles.foldoutHeaderIcon, GUILayout.Width(16.0f))
|| (clickArea.Contains(current.mousePosition) && current.type == EventType.ContextClick))
{
ShowItemMenu(buildTargetGroup, task);
if (current.type == EventType.ContextClick)
{
current.Use();
}
}
EditorGUILayout.EndHorizontal();
}
private void DrawMoreActionsMenuList(BuildTargetGroup buildTargetGroup)
{
var current = Event.current;
if (GUILayout.Button("", EditorStyles.foldoutHeaderIcon, GUILayout.Width(16.0f)))
{
var menu = new GenericMenu();
menu.AddItem(RefreshTasksButtonContent, false, OnRefresh, new object[] { buildTargetGroup });
menu.AddItem(GenerateReportButtonContent, false, OnGenerateReport, new object[] { buildTargetGroup });
menu.ShowAsContext();
if (current.type == EventType.ContextClick)
{
current.Use();
}
}
}
private void ReadContextMenuArguments(
object arg,
out BuildTargetGroup buildTargetGroup,
out OVRConfigurationTask task)
{
var args = arg as object[];
buildTargetGroup = args != null ? (BuildTargetGroup)args[0] : BuildTargetGroup.Unknown;
task = args?[1] as OVRConfigurationTask;
}
private void OnIgnore(object args)
{
ReadContextMenuArguments(args, out var buildTargetGroup, out var task);
var ignore = !task.IsIgnored(buildTargetGroup);
if (ignore)
{
OVRProjectSetupSettingsProvider.SetNewInteraction(OVRProjectSetupSettingsProvider.Interaction.Ignored);
}
task?.SetIgnored(buildTargetGroup, ignore);
}
private void OnDocumentation(object args)
{
OVRProjectSetupSettingsProvider.SetNewInteraction(OVRProjectSetupSettingsProvider.Interaction
.WentToDocumentation);
ReadContextMenuArguments(args, out var buildTargetGroup, out var task);
var url = task?.URL.GetValue(buildTargetGroup);
Application.OpenURL(url);
}
private void OnGoToSourceCode(object args)
{
OVRProjectSetupSettingsProvider.SetNewInteraction(OVRProjectSetupSettingsProvider.Interaction.WentToSource);
ReadContextMenuArguments(args, out var buildTargetGroup, out var task);
task?.SourceCode.Open();
}
private void OnGenerateReport(object arg)
{
var buildTargetGroup = arg is object[] args ? (BuildTargetGroup)args[0] : BuildTargetGroup.Unknown;
var path = EditorUtility.OpenFolderPanel(OutFolderTitle, "", "");
if (string.IsNullOrEmpty(path)) return;
try
{
var reportFileName = GenerateReport(buildTargetGroup, path);
EditorUtility.DisplayDialog(SuccessTitle, $"{ReportGenerationSuccessMessage}\n{reportFileName}", OkButton);
}
catch (Exception e)
{
EditorUtility.DisplayDialog(ErrorTitle, $"{ReportGenerationErrorMessage}\n{e.Message}", OkButton);
}
}
private void OnRefresh(object arg)
{
var buildTargetGroup = arg is object[] args ? (BuildTargetGroup)args[0] : BuildTargetGroup.Unknown;
try
{
OVRProjectSetup.UpdateTasks(buildTargetGroup, logMessages: OVRProjectSetup.LogMessages.Disabled,
blocking: true);
EditorUtility.DisplayDialog(SuccessTitle, TasksRefreshSuccessMessage, OkButton);
}
catch (Exception e)
{
EditorUtility.DisplayDialog(ErrorTitle, $"{TasksRefreshErrorMessage}\n{e.Message}", OkButton);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 16be1d6ef5ab58848a7b44f62ab8d345
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,124 @@
/*
* 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 System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
[Serializable]
internal class OVRConfigurationTaskJsonReport
{
public string uid;
public string group;
public string message;
public string level;
public bool isDone;
}
[Serializable]
internal class OVRProjectSetupJsonReport
{
public string createdAt;
public string buildTargetGroup;
public string projectName;
public string unityVersion;
public string projectUrl;
public List<OVRConfigurationTaskJsonReport> tasksStatus;
}
internal class OVRProjectSetupReport
{
public const string ReportDefaultFileNamePrefix = "setuptoolreport";
public const string ReportDefaultFileNameDateTimeFormat = "yyyy-dd-MM--HH-mm-ss";
public const string ReportDefaultOutputPath = "./";
/// <summary>
/// Generate a JSON report and writes it in a JSON file at the given output path.
/// </summary>
/// <param name="tasks">The tasks that will be included in the report.</param>
/// <param name="buildTargetGroup">Platform for which this report applies.</param>
/// <param name="outputPath">The path where the report file will be written. If null, the default output path will be used.</param>
/// <param name="fileName">The name of the generated report file. If null, a name will be generated.</param>
/// <returns>Returns the full path to the created report file, including the file name.</returns>
public static string GenerateJson(
IEnumerable<OVRConfigurationTask> tasks,
BuildTargetGroup buildTargetGroup,
string outputPath = null,
string fileName = null
)
{
var report = BuildSerializableReport(tasks, buildTargetGroup);
var creationTime = DateTime.Parse(report.createdAt);
var outputFilePath =
Path.Combine(outputPath ?? ReportDefaultOutputPath, fileName ?? GenerateFileName(creationTime));
try
{
var jsonString = JsonUtility.ToJson(report, prettyPrint: true);
File.WriteAllText(outputFilePath, jsonString);
}
catch (Exception e)
{
throw new Exception("Could not write project setup report", e);
}
return outputFilePath;
}
private static string GenerateFileName(DateTime creationTime)
{
return ReportDefaultFileNamePrefix + "_" + creationTime.ToString(ReportDefaultFileNameDateTimeFormat) + ".json";
}
private static OVRProjectSetupJsonReport BuildSerializableReport(
IEnumerable<OVRConfigurationTask> tasks,
BuildTargetGroup buildTargetGroup
)
{
var tasksReports = tasks.Select(t => new OVRConfigurationTaskJsonReport
{
uid = t.Uid.ToString(),
group = t.Group.ToString(),
message = t.Message.GetValue(buildTargetGroup).ToString(),
level = t.Level.GetValue(buildTargetGroup).ToString(),
isDone = t.IsDone(buildTargetGroup)
})
.ToList();
var report = new OVRProjectSetupJsonReport
{
createdAt = DateTime.Now.ToUniversalTime().ToString(),
buildTargetGroup = buildTargetGroup.ToString(),
projectName = PlayerSettings.productName,
unityVersion = Application.unityVersion,
projectUrl = RemoveSuffix(Application.dataPath, "/Assets"),
tasksStatus = tasksReports
};
return report;
}
private static string RemoveSuffix(string source, string suffix)
{
return source.EndsWith(suffix) ? source.Remove(source.LastIndexOf(suffix, StringComparison.Ordinal)) : source;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a220840af68244f0b032b4bd1c7304b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,283 @@
/*
* 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 abstract class OVRProjectSetupSettingItem<T>
{
public T Default { get; }
public string Uid { get; }
public string Label { get; }
public string Key { get; }
public abstract T Value { get; set; }
protected OVRProjectSetupSettingItem(string uid, T defaultValue, string label = null)
{
Default = defaultValue;
Uid = uid;
Label = label ?? uid;
Key = OVRProjectSetup.KeyPrefix + "." + Uid;
}
public abstract void AppendToMenu(GenericMenu menu);
public void Reset()
{
Value = Default;
}
public void OnSet()
{
OVRTelemetry.Start(OVRProjectSetupTelemetryEvent.EventTypes.Option)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Uid, Uid)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Value, Value.ToString())
.Send();
}
}
internal abstract class OVRProjectSetupSettingBool : OVRProjectSetupSettingItem<bool>
{
protected OVRProjectSetupSettingBool(string uid, bool defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override void AppendToMenu(GenericMenu menu)
{
menu.AddItem(new GUIContent(Label), Value, () => Value = !Value);
}
}
internal abstract class OVRProjectSetupSettingFloat : OVRProjectSetupSettingItem<float>
{
protected OVRProjectSetupSettingFloat(string uid, float defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override void AppendToMenu(GenericMenu menu)
{
// Do not Append to a GenericMenu
}
}
internal class OVRProjectSetupOnlyOnceSettingBool : OVRProjectSetupSettingBool
{
private static readonly HashSet<string> OnlyOnceSettings = new HashSet<string>();
public OVRProjectSetupOnlyOnceSettingBool(string uid) : base(uid, true)
{
Init();
}
private void Init()
{
previousTimestamp = new OVRProjectSetupInternalUserSettingFloat($"{Uid}_timestamp", 0.0f);
previousTimeSinceStartup = new OVRProjectSetupInternalUserSettingFloat($"{Uid}_timesincestartup", 0.0f);
}
private OVRProjectSetupSettingFloat previousTimestamp;
private OVRProjectSetupSettingFloat previousTimeSinceStartup;
public override bool Value
{
get => OnlyOnce();
set
{
if (value == Default)
{
// If back to Default, we remove it from the dictionary to avoid clutter
OnlyOnceSettings.Remove(Uid);
previousTimestamp.Reset();
previousTimeSinceStartup.Reset();
}
}
}
private bool OnlyOnce()
{
if (OnlyOnceSettings.Contains(Uid))
{
// If the tuple was found, this means we already went through this test
// So either it was the first time the previous time
// or it wasn't the first time...so neither is current time
return false;
}
// From now on, we can be sure next time won't be the first
// So we add it to the HashSet
OnlyOnceSettings.Add(Uid);
var currentTimestamp = (float)DateTime.UtcNow.TimeOfDay.TotalSeconds;
// Better timestamp would be absolute number of seconds
// But this is too big to be stored in float or int, and EditorPrefs do not allow double or long.
var currentTimeSinceStartup = (float)EditorApplication.timeSinceStartup;
// The tuple was not found, so this is the first time we're testing it
// since last compile
// We're getting the previous saved timestamps
var timeStampDiff = currentTimestamp - previousTimestamp.Value;
var timeSinceStartupDiff = currentTimeSinceStartup - previousTimeSinceStartup.Value;
// If the difference between timestamps is very close
// to the difference between timeSinceStartups
// Then we're very probably on the same instance of the Editor
const float closeThreshold = 5.0f;
if (Mathf.Abs(timeSinceStartupDiff - timeStampDiff) < closeThreshold)
{
return false;
}
// And we're storing the current timestamp for next time
previousTimestamp.Value = currentTimestamp;
previousTimeSinceStartup.Value = currentTimeSinceStartup;
return true;
}
}
internal class OVRProjectSetupInternalUserSettingFloat : OVRProjectSetupSettingFloat
{
public OVRProjectSetupInternalUserSettingFloat(string uid, float defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override float Value
{
get => EditorPrefs.GetFloat(Key, Default);
set => EditorPrefs.SetFloat(Key, value);
}
}
internal class OVRProjectSetupInternalUserSettingBool : OVRProjectSetupSettingBool
{
public OVRProjectSetupInternalUserSettingBool(string uid, bool defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override bool Value
{
get => EditorPrefs.GetBool(Key, Default);
set => EditorPrefs.SetBool(Key, value);
}
}
internal class OVRProjectSetupUserSettingFloat : OVRProjectSetupInternalUserSettingFloat
{
public OVRProjectSetupUserSettingFloat(string uid, float defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override float Value
{
set
{
base.Value = value;
OnSet();
}
}
}
internal class OVRProjectSetupUserSettingBool : OVRProjectSetupInternalUserSettingBool
{
public OVRProjectSetupUserSettingBool(string uid, bool defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override bool Value
{
set
{
base.Value = value;
OnSet();
}
}
}
internal class OVRProjectSettingBool : OVRProjectSetupSettingBool
{
public OVRProjectSettingBool(string uid, bool defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override bool Value
{
get => OVRProjectSetupSettings.GetProjectConfig(create: false)?.GetProjectSetupBool(Key, Default) ?? Default;
set
{
OVRProjectSetupSettings.GetProjectConfig()?.SetProjectSetupBool(Key, value);
OnSet();
}
}
public bool HasRecordedValue => OVRProjectSetupSettings.GetProjectConfig(create: false)?.HasBool(Key) ?? false;
}
internal class OVRProjectSetupProjectSettingBool : OVRProjectSetupSettingBool
{
public OVRProjectSetupProjectSettingBool(string uid, bool defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override bool Value
{
get => OVRProjectSetupSettings.GetProjectConfig(create: false)?.GetProjectSetupBool(Key, Default) ?? Default;
set
{
if (value == Default)
{
// If back to Default, we remove it from the dictionary to avoid clutter
OVRProjectSetupSettings.GetProjectConfig()?.RemoveProjectSetupBool(Key);
}
else
{
OVRProjectSetupSettings.GetProjectConfig()?.SetProjectSetupBool(Key, value);
}
OnSet();
}
}
}
internal class OVRProjectSetupConstSettingBool : OVRProjectSetupSettingBool
{
public OVRProjectSetupConstSettingBool(string uid, bool defaultValue, string label = null)
: base(uid, defaultValue, label)
{
}
public override bool Value
{
get => Default;
set { }
}
public override void AppendToMenu(GenericMenu menu)
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 63422cd755014f419520a814453c957e
timeCreated: 1661871624

View File

@ -0,0 +1,108 @@
/*
* 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 UnityEngine;
using UnityEditor;
using System;
[System.Serializable]
public class OVRProjectSetupSettings : ScriptableObject
{
[Serializable]
public class BoolProperties : SerializableDictionary<string, bool>
{
}
private const string AssetName = "OculusProjectSetupSettings.asset";
[SerializeField] private BoolProperties boolProperties = new BoolProperties();
private static OVRProjectSetupSettings _config = null;
private static string _configPath = null;
public bool HasBool(string key)
{
return boolProperties.ContainsKey(key);
}
public bool GetProjectSetupBool(string key, bool defaultValue)
{
if (!boolProperties.TryGetValue(key, out var value))
{
// To avoid clutter, getter doesn't add to the dictionary
value = defaultValue;
}
return value;
}
public void SetProjectSetupBool(string key, bool value)
{
boolProperties[key] = value;
EditorUtility.SetDirty(this);
}
public void RemoveProjectSetupBool(string key)
{
boolProperties.Remove(key);
EditorUtility.SetDirty(this);
}
private static string GetOculusProjectConfigAssetPath(bool refresh = false)
{
if (_configPath != null && !refresh)
{
return _configPath;
}
// Using the same Path logic as OVRProjectConfig
_configPath = OVRProjectConfig.ComputeOculusProjectAssetPath(AssetName);
return _configPath;
}
public static OVRProjectSetupSettings GetProjectConfig(bool refresh = false, bool create = true)
{
if (_config != null && !refresh)
{
return _config;
}
var oculusProjectConfigAssetPath = GetOculusProjectConfigAssetPath(refresh: false);
try
{
_config = AssetDatabase.LoadAssetAtPath(oculusProjectConfigAssetPath,
typeof(OVRProjectSetupSettings)) as OVRProjectSetupSettings;
}
catch (System.Exception e)
{
Debug.LogWarningFormat("Unable to load ProjectSetupConfig from {0}, error {1}",
oculusProjectConfigAssetPath, e.Message);
}
if (_config == null && create && !BuildPipeline.isBuildingPlayer)
{
Debug.LogFormat("Creating ProjectSetupConfig at path {0}", oculusProjectConfigAssetPath);
_config = ScriptableObject.CreateInstance<OVRProjectSetupSettings>();
AssetDatabase.CreateAsset(_config, oculusProjectConfigAssetPath);
}
return _config;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 939e07d58bc74256b6cb58d86fe35a56
timeCreated: 1663663006

View File

@ -0,0 +1,159 @@
/*
* 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.Globalization;
using UnityEditor;
using UnityEngine.UIElements;
internal class OVRProjectSetupSettingsProvider : SettingsProvider
{
public enum Origins
{
Settings,
Menu,
Icon,
Console
}
public enum Interaction
{
None,
WentToDocumentation,
WentToSource,
Fixed,
Ignored
}
[MenuItem("Oculus/Tools/Project Setup Tool", false, 1)]
static void OpenProjectSetupTool()
{
OpenSettingsWindow(Origins.Menu);
}
public const string SettingsName = "Oculus";
public static readonly string SettingsPath = $"Project/{SettingsName}";
private OVRProjectSetupDrawer _ovrProjectSetupDrawer;
private OVRProjectSetupDrawer OvrProjectSetupDrawer => _ovrProjectSetupDrawer ??= new OVRProjectSetupDrawer();
private static Origins? _lastOrigin = null;
private static Interaction _lastInteraction = Interaction.None;
private static bool _activated = false;
public static double OpenTimestamp { get; set; }
public static double TimeSpent => EditorApplication.timeSinceStartup - OpenTimestamp;
public static OVRTelemetryMarker? InteractionFlowEvent { get; set; }
[SettingsProvider]
public static SettingsProvider CreateProjectValidationSettingsProvider()
{
return new OVRProjectSetupSettingsProvider(SettingsPath, SettingsScope.Project);
}
internal static void SetNewInteraction(Interaction interaction)
{
if (interaction > _lastInteraction)
{
InteractionFlowEvent = InteractionFlowEvent?.AddPoint(OVRProjectSetupTelemetryEvent.MarkerPoints.Interact);
_lastInteraction = interaction;
}
}
internal static void ResetInteraction()
{
InteractionFlowEvent = null;
_lastInteraction = Interaction.None;
_lastOrigin = null;
_activated = false;
OpenTimestamp = 0.0;
}
private OVRProjectSetupSettingsProvider(string path,
SettingsScope scopes)
: base(path, scopes)
{
}
public override void OnActivate(string searchContext, VisualElement rootElement)
{
if (!_activated)
{
OpenTimestamp = EditorApplication.timeSinceStartup;
_activated = true;
_lastOrigin = _lastOrigin ?? Origins.Settings;
OVRTelemetry.Start(OVRProjectSetupTelemetryEvent.EventTypes.Open)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.BuildTargetGroup,
EditorUserBuildSettings.selectedBuildTargetGroup.ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Origin, _lastOrigin.ToString())
.Send();
InteractionFlowEvent = InteractionFlowEvent?.AddPoint(OVRProjectSetupTelemetryEvent.MarkerPoints.Open)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Origin, _lastOrigin.ToString());
}
}
public override void OnDeactivate()
{
if (TimeSpent < 0.1)
{
// Ignore the entire interaction as it was too short to be meaningful
return;
}
if (_activated)
{
OVRTelemetry.Start(OVRProjectSetupTelemetryEvent.EventTypes.Close)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.BuildTargetGroup,
EditorUserBuildSettings.selectedBuildTargetGroup.ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Origin, _lastOrigin.ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.TimeSpent,
TimeSpent.ToString(CultureInfo.InvariantCulture))
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Interaction, _lastInteraction.ToString())
.Send();
InteractionFlowEvent = InteractionFlowEvent?.AddPoint(OVRProjectSetupTelemetryEvent.MarkerPoints.Close)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Interaction, _lastInteraction.ToString())
.Send();
ResetInteraction();
}
}
public override void OnTitleBarGUI()
{
base.OnTitleBarGUI();
OvrProjectSetupDrawer.OnTitleBarGUI();
}
public override void OnGUI(string searchContext)
{
base.OnGUI(searchContext);
OvrProjectSetupDrawer.OnGUI();
}
public static void OpenSettingsWindow(Origins origin)
{
_lastOrigin = origin;
var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
EditorUserBuildSettings.selectedBuildTargetGroup = buildTargetGroup;
SettingsService.OpenProjectSettings(SettingsPath);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7cef00c42850e534eb89eba031054a2b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,182 @@
/*
* 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.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using Object = UnityEngine.Object;
[InitializeOnLoad]
internal static class OVRProjectSetupStatusIcon
{
private static readonly Type _toolbarType;
private static readonly PropertyInfo _guiBackend;
private static readonly PropertyInfo _visualTree;
private static readonly FieldInfo _onGuiHandler;
private static readonly OVRGUIContent _iconSuccess;
private static readonly OVRGUIContent _iconNeutral;
private static readonly OVRGUIContent _iconWarning;
private static readonly OVRGUIContent _iconError;
private static readonly string OpenOculusSettings = "Open Oculus Settings";
private static GUIStyle _iconStyle;
private static OVRGUIContent _currentIcon;
private static Object _appStatusBar;
private static VisualElement _container;
internal static OVRGUIContent CurrentIcon => _currentIcon;
static OVRProjectSetupStatusIcon()
{
if (!OVREditorUtils.IsMainEditor()) return;
var editorAssembly = typeof(UnityEditor.Editor).Assembly;
var bindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
_toolbarType = editorAssembly.GetType("UnityEditor.AppStatusBar");
var guiViewType = editorAssembly.GetType("UnityEditor.GUIView");
var backendType = editorAssembly.GetType("UnityEditor.IWindowBackend");
var containerType = typeof(IMGUIContainer);
_guiBackend = guiViewType?.GetProperty("windowBackend", bindingFlags);
_visualTree = backendType?.GetProperty("visualTree", bindingFlags);
_onGuiHandler = containerType?.GetField("m_OnGUIHandler", bindingFlags);
_iconSuccess = OVREditorUtils.CreateContent("ovr_icon_success.png", OVRGUIContent.Source.GenericIcons);
_iconNeutral = OVREditorUtils.CreateContent("ovr_icon_neutral.png", OVRGUIContent.Source.GenericIcons);
_iconWarning = OVREditorUtils.CreateContent("ovr_icon_warning.png", OVRGUIContent.Source.GenericIcons);
_iconError = OVREditorUtils.CreateContent("ovr_icon_error.png", OVRGUIContent.Source.GenericIcons);
_currentIcon = _iconSuccess;
OVRProjectSetup.ProcessorQueue.OnProcessorCompleted += RefreshData;
EditorApplication.update += Update;
}
private static void Update()
{
if (_appStatusBar == null)
{
Refresh();
}
}
private static void Refresh()
{
var toolbars = Resources.FindObjectsOfTypeAll(_toolbarType);
if (toolbars == null || toolbars.Length == 0)
{
return;
}
_appStatusBar = toolbars[0];
var backend = _guiBackend?.GetValue(_appStatusBar);
if (backend == null)
{
return;
}
var elements = _visualTree?.GetValue(backend, null) as VisualElement;
_container = elements?[0];
if (_container == null)
{
return;
}
var handler = _onGuiHandler?.GetValue(_container) as Action;
if (handler == null)
{
return;
}
handler -= RefreshGUI;
handler += RefreshGUI;
_onGuiHandler.SetValue(_container, handler);
}
private static void RefreshStyles()
{
if (_iconStyle != null)
{
return;
}
_iconStyle = new GUIStyle("StatusBarIcon");
}
public static OVRGUIContent ComputeIcon(OVRConfigurationTaskUpdaterSummary summary)
{
if (summary == null)
{
return _iconSuccess;
}
var icon = summary.HighestFixLevel switch
{
OVRProjectSetup.TaskLevel.Optional => _iconNeutral,
OVRProjectSetup.TaskLevel.Recommended => _iconWarning,
OVRProjectSetup.TaskLevel.Required => _iconError,
_ => _iconSuccess
};
icon.Tooltip = $"{summary.ComputeNoticeMessage()}\n{OpenOculusSettings}";
return icon;
}
private static void RefreshData(OVRConfigurationTaskProcessor processor)
{
var activeBuildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
if (processor.Type == OVRConfigurationTaskProcessor.ProcessorType.Updater
&& processor.BuildTargetGroup == activeBuildTargetGroup)
{
var updater = processor as OVRConfigurationTaskUpdater;
_currentIcon = ComputeIcon(updater?.Summary);
}
}
private static void RefreshGUI()
{
if (!OVRProjectSetup.ShowStatusIcon.Value)
{
return;
}
RefreshStyles();
var screenWidth = _container.layout.width;
// Hardcoded position
// Currently overlaps with progress bar, and works with 2020 status bar icons
// TODO: Better hook to dynamically position the button
var currentRect = new Rect(screenWidth - 130, 0, 26, 30); // Hardcoded position
GUILayout.BeginArea(currentRect);
if (GUILayout.Button(_currentIcon, _iconStyle))
{
OVRStatusMenu.ShowDropdown(GUIUtility.GUIToScreenPoint(Vector2.zero));
}
var buttonRect = GUILayoutUtility.GetLastRect();
EditorGUIUtility.AddCursorRect(buttonRect, MouseCursor.Link);
GUILayout.EndArea();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2e429af8ad0c53041b56e07532521492
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,109 @@
/*
* 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 UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine.SceneManagement;
[InitializeOnLoad]
internal static class OVRProjectSetupUpdater
{
private static readonly string EnabledSettingItemName = "BackgroundChecks";
private static readonly string EnabledSettingItemLabel = "Background Checks";
internal static OVRProjectSetupSettingBool Enabled;
public static readonly OVRProjectSetupSettingBool ShowLogsOnlyOnce =
new OVRProjectSetupOnlyOnceSettingBool("ShowLogsOnlyOnce");
private static readonly double StatusUpdateWatchdogTimer = 5.0;
private static double _lastStatusUpdate;
internal static void SetupTemporaryRegistry()
{
Enabled = new OVRProjectSetupConstSettingBool(OVRProjectSetupUpdater.EnabledSettingItemName, false,
OVRProjectSetupUpdater.EnabledSettingItemLabel);
}
internal static void RestoreRegistry()
{
Enabled = new OVRProjectSetupProjectSettingBool(OVRProjectSetupUpdater.EnabledSettingItemName, true,
OVRProjectSetupUpdater.EnabledSettingItemLabel);
}
static OVRProjectSetupUpdater()
{
EditorSceneManager.sceneOpened += OnEditorSceneManagerSceneOpened;
EditorApplication.update += WatchdogUpdate;
}
private static void WatchdogUpdate()
{
var currentTime = EditorApplication.timeSinceStartup;
if (currentTime - _lastStatusUpdate > StatusUpdateWatchdogTimer)
{
Update();
}
}
private static void OnEditorSceneManagerSceneOpened(Scene scene, OpenSceneMode mode)
{
Update();
}
private static void Update()
{
ResetWatchdog();
if (!Enabled.Value)
{
return;
}
if (EditorApplication.isPlayingOrWillChangePlaymode)
{
return;
}
if (OVRProjectSetup.ProcessorQueue.Busy)
{
return;
}
var buildTargetGroup = BuildPipeline.GetBuildTargetGroup(EditorUserBuildSettings.activeBuildTarget);
var logOption = (OVRProjectSetup.AllowLogs.Value || ShowLogsOnlyOnce.Value)
? OVRProjectSetup.LogMessages.Summary
: OVRProjectSetup.LogMessages.Disabled;
OVRProjectSetup.UpdateTasks(buildTargetGroup, logMessages: logOption, blocking: false,
onCompleted: OnUpdateCompleted);
}
private static void OnUpdateCompleted(OVRConfigurationTaskProcessor processor)
{
if (processor.Type == OVRConfigurationTaskProcessor.ProcessorType.Updater)
{
ResetWatchdog();
}
}
private static void ResetWatchdog()
{
_lastStatusUpdate = EditorApplication.timeSinceStartup;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 96cefb92e9ef4844a95e7350ef584e5e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,157 @@
/*
* 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.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
using UnityEngine.SceneManagement;
internal static class OVRProjectSetupUtils
{
public static T FindComponentInScene<T>() where T : Component
{
var scene = SceneManager.GetActiveScene();
var rootGameObjects = scene.GetRootGameObjects();
return rootGameObjects.FirstOrDefault(go => go.GetComponentInChildren<T>())?.GetComponentInChildren<T>();
}
public static List<T> FindComponentsInScene<T>() where T : Component
{
var activeScene = SceneManager.GetActiveScene();
var foundComponents = new List<T>();
var rootObjects = activeScene.GetRootGameObjects();
foreach (var rootObject in rootObjects)
{
var components = rootObject.GetComponentsInChildren<T>(true);
foundComponents.AddRange(components);
}
return foundComponents;
}
public static bool HasComponentInParents<T>(GameObject obj) where T : Component
{
var currentTransform = obj.transform;
while (currentTransform != null)
{
if (currentTransform.GetComponent<T>() != null)
{
return true;
}
currentTransform = currentTransform.parent;
}
return false;
}
public static T FindScriptableObjectInProject<T>() where T : ScriptableObject
{
var guids = AssetDatabase.FindAssets("t:" + typeof(T).Name);
if (guids.Length == 0)
{
return null;
}
var path = AssetDatabase.GUIDToAssetPath(guids[0]);
return AssetDatabase.LoadAssetAtPath<T>(path);
}
private static ListRequest _packageManagerListRequest;
static OVRProjectSetupUtils()
{
RefreshPackageList(false);
OVRGUIContent.RegisterContentPath(OVRGUIContent.Source.ProjectSetupToolIcons, "OVRProjectSetup/Icons");
}
public static bool PackageManagerListAvailable => _packageManagerListRequest.Status == StatusCode.Success;
public static bool IsPackageInstalled(string packageName) =>
PackageManagerListAvailable &&
(_packageManagerListRequest.Result?.Any(package => package.name == packageName) ?? false);
public static bool RefreshPackageList(bool blocking)
{
_packageManagerListRequest = Client.List(offlineMode: false, includeIndirectDependencies: true);
if (blocking)
{
while (!PackageManagerListAvailable)
{
Thread.Sleep(100);
}
}
return PackageManagerListAvailable;
}
public static bool InstallPackage(string packageName)
{
var request = Client.Add(packageName);
// TODO: make this async later
while (!request.IsCompleted)
{
Thread.Sleep(100);
}
// Refresh the Client list
RefreshPackageList(false);
return request.Status == StatusCode.Success;
}
public static bool UninstallPackage(string packageName)
{
var request = Client.Remove(packageName);
// TODO: make this async later
while (!request.IsCompleted)
{
Thread.Sleep(1);
}
// Refresh the Client list
RefreshPackageList(false);
return request.Status == StatusCode.Success;
}
public static BuildTarget GetBuildTarget(this BuildTargetGroup buildTargetGroup)
{
// It is a bit tricky to get the build target from the build target group
// because of some additional variations on build targets that the build target group doesn't know about
// This function aims at offering an approximation of the build target, but it's not guaranteed
return buildTargetGroup switch
{
BuildTargetGroup.Android => BuildTarget.Android,
BuildTargetGroup.Standalone => BuildTarget.StandaloneWindows64,
_ => BuildTarget.NoTarget
};
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8c9cf42992bd9243b91495e0bee3883
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: fe0a0d59f1f7e8f4f880b0e61e0488e3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 4b1b824db73a75642b72bb9ecff9c88e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,144 @@
/*
* 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 UnityEditor;
[InitializeOnLoad]
internal static class OVRProjectSetupCompatibilityTasks
{
public static bool IsTargetingARM64 =>
(PlayerSettings.Android.targetArchitectures & AndroidArchitecture.ARM64) != 0;
public static readonly Action<BuildTargetGroup> SetARM64Target = (buildTargetGroup) =>
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64;
static OVRProjectSetupCompatibilityTasks()
{
var compatibilityTaskGroup = OVRProjectSetup.TaskGroup.Compatibility;
// [Required] Platform has to be supported
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: compatibilityTaskGroup,
isDone: OVRProjectSetup.IsPlatformSupported,
conditionalMessage: buildTargetGroup =>
OVRProjectSetup.IsPlatformSupported(buildTargetGroup)
? $"Build Target ({buildTargetGroup}) is supported"
: $"Build Target ({buildTargetGroup}) is not supported"
);
// [Required] Android minimum level API
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: compatibilityTaskGroup,
platform: BuildTargetGroup.Android,
isDone: buildTargetGroup => PlayerSettings.Android.minSdkVersion >= AndroidSdkVersions.AndroidApiLevel29,
message: "Minimum Android API Level must be at least 29",
fix: buildTargetGroup => PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel29,
fixMessage: "PlayerSettings.Android.minSdkVersion = AndroidSdkVersions.AndroidApiLevel29"
);
// [Required] Android target level API
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: compatibilityTaskGroup,
platform: BuildTargetGroup.Android,
isDone: buildTargetGroup =>
PlayerSettings.Android.targetSdkVersion == AndroidSdkVersions.AndroidApiLevelAuto ||
PlayerSettings.Android.targetSdkVersion >= AndroidSdkVersions.AndroidApiLevel29,
message: "Target API should be set to \"Automatic\" as to ensure latest version",
fix: buildTargetGroup => PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevelAuto,
fixMessage: "PlayerSettings.Android.targetSdkVersion = AndroidSdkVersions.AndroidApiLevelAuto"
);
// [Required] Install Location
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: compatibilityTaskGroup,
platform: BuildTargetGroup.Android,
isDone: buildTargetGroup =>
PlayerSettings.Android.preferredInstallLocation == AndroidPreferredInstallLocation.Auto,
message: "Install Location should be set to \"Automatic\"",
fix: buildTargetGroup =>
PlayerSettings.Android.preferredInstallLocation = AndroidPreferredInstallLocation.Auto,
fixMessage: "PlayerSettings.Android.preferredInstallLocation = AndroidPreferredInstallLocation.Auto"
);
// [Required] Generate Android Manifest
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Optional,
group: compatibilityTaskGroup,
platform: BuildTargetGroup.Android,
isDone: buildTargetGroup => OVRManifestPreprocessor.DoesAndroidManifestExist(),
message: "An Android Manifest file is required",
fix: buildTargetGroup => OVRManifestPreprocessor.GenerateManifestForSubmission(),
fixMessage: "Generates a default Manifest file"
);
// ConfigurationTask : IL2CPP when ARM64
OVRProjectSetup.AddTask(
conditionalLevel: buildTargetGroup =>
IsTargetingARM64 ? OVRProjectSetup.TaskLevel.Required : OVRProjectSetup.TaskLevel.Recommended,
group: compatibilityTaskGroup,
platform: BuildTargetGroup.Android,
isDone: buildTargetGroup =>
PlayerSettings.GetScriptingBackend(buildTargetGroup) == ScriptingImplementation.IL2CPP,
conditionalMessage: buildTargetGroup =>
IsTargetingARM64
? "Building the ARM64 architecture requires using IL2CPP as the scripting backend"
: "Using IL2CPP as the scripting backend is recommended",
fix: buildTargetGroup =>
PlayerSettings.SetScriptingBackend(buildTargetGroup, ScriptingImplementation.IL2CPP),
fixMessage: "PlayerSettings.SetScriptingBackend(buildTargetGroup, ScriptingImplementation.IL2CPP)"
);
// ConfigurationTask : ARM64 is recommended
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: compatibilityTaskGroup,
platform: BuildTargetGroup.Android,
isDone: buildTargetGroup => IsTargetingARM64,
message: "Use ARM64 as target architecture",
fix: SetARM64Target,
fixMessage: "PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64"
);
// ConfigurationTask : No Alpha or Beta for production
// This is a task that CANNOT BE FIXED
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: compatibilityTaskGroup,
isDone: group => !OVRManager.IsUnityAlphaOrBetaVersion(),
message: "We recommend using a stable version for Oculus Development"
);
// ConfigurationTask : Check that Android TV Compatibility is disabled
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
platform: BuildTargetGroup.Android,
group: compatibilityTaskGroup,
isDone: group => !PlayerSettings.Android.androidTVCompatibility,
message: "Apps with Android TV Compatibility enabled are not accepted by the Oculus Store",
fix: group => PlayerSettings.Android.androidTVCompatibility = false,
fixMessage: "PlayerSettings.Android.androidTVCompatibility = false"
);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f23b5d0d61a07874aa97d72200848188
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
/*
* 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.
*/
/*
That file was intentionally removed.
*/

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fc6140a65ceb57243bfbd2ffffe5fc98
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,100 @@
/*
* 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 UnityEditor;
using UnityEngine;
[InitializeOnLoad]
internal static class OVRProjectSetupMovementSDKTasks2
{
private const OVRProjectSetup.TaskGroup Group = OVRProjectSetup.TaskGroup.Features;
static OVRProjectSetupMovementSDKTasks2()
{
AddMovementTrackingTasks<OVRBody>(
"Body Tracking",
() => OVRProjectConfig.CachedProjectConfig.bodyTrackingSupport,
ovrManager => ovrManager.requestBodyTrackingPermissionOnStartup,
projectConfig => projectConfig.bodyTrackingSupport = OVRProjectConfig.FeatureSupport.Supported,
ovrManager => ovrManager.requestBodyTrackingPermissionOnStartup = true);
AddMovementTrackingTasks<OVRFaceExpressions>(
"Face Tracking",
() => OVRProjectConfig.CachedProjectConfig.faceTrackingSupport,
ovrManager => ovrManager.requestFaceTrackingPermissionOnStartup,
projectConfig => projectConfig.faceTrackingSupport = OVRProjectConfig.FeatureSupport.Supported,
ovrManager => ovrManager.requestFaceTrackingPermissionOnStartup = true);
AddMovementTrackingTasks<OVREyeGaze>(
"Eye Tracking",
() => OVRProjectConfig.CachedProjectConfig.eyeTrackingSupport,
ovrManager => ovrManager.requestEyeTrackingPermissionOnStartup,
projectConfig => projectConfig.eyeTrackingSupport = OVRProjectConfig.FeatureSupport.Supported,
ovrManager => ovrManager.requestEyeTrackingPermissionOnStartup = true);
}
private static void AddMovementTrackingTasks<T>(string featureName,
Func<OVRProjectConfig.FeatureSupport> supportLevel, Func<OVRManager, bool> permissionRequested,
Action<OVRProjectConfig> enableSupport, Action<OVRManager> enablePermissionRequest) where T : Component
{
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: buildTargetGroup => OVRProjectSetupUtils.FindComponentInScene<T>() == null ||
supportLevel() != OVRProjectConfig.FeatureSupport.None,
message: $"When using {featureName} in your project it's required to enable its capability " +
$"in the project config",
fix: buildTargetGroup =>
{
var projectConfig = OVRProjectConfig.CachedProjectConfig;
enableSupport(projectConfig);
OVRProjectConfig.CommitProjectConfig(projectConfig);
},
fixMessage: $"Enable {featureName} support in the project config"
);
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: buildTargetGroup =>
{
if (supportLevel() == OVRProjectConfig.FeatureSupport.None)
{
return true;
}
var ovrManager = OVRProjectSetupUtils.FindComponentInScene<OVRManager>();
return !ovrManager || permissionRequested(ovrManager);
},
message: $"Automatically request the {featureName} permission on startup",
fix: buildTargetGroup =>
{
var ovrManager = OVRProjectSetupUtils.FindComponentInScene<OVRManager>();
if (ovrManager != null)
{
enablePermissionRequest(ovrManager);
EditorUtility.SetDirty(ovrManager);
}
},
fixMessage: $"Request {featureName} permission on startup"
);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0b59f40a4e9d6f340a944dbaa75354ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
/*
* 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.
*/
/*
That file was intentionally removed.
*/

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1cae49aff62b1d24abd59636906cf874
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,110 @@
/*
* 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 UnityEditor;
[InitializeOnLoad]
internal static class OVRProjectSetupPassthrough
{
private const OVRProjectSetup.TaskGroup Group = OVRProjectSetup.TaskGroup.Features;
static OVRProjectSetupPassthrough()
{
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: buildTargetGroup => OVRProjectSetupUtils.FindComponentInScene<OVRPassthroughLayer>() == null ||
OVRProjectConfig.CachedProjectConfig.insightPassthroughSupport !=
OVRProjectConfig.FeatureSupport.None,
message: "When using Passthrough in your project it's required to enable its capability " +
"in the project config",
fix: buildTargetGroup =>
{
var projectConfig = OVRProjectConfig.CachedProjectConfig;
projectConfig.insightPassthroughSupport =
OVRProjectConfig.FeatureSupport.Supported;
OVRProjectConfig.CommitProjectConfig(projectConfig);
},
fixMessage: "Enable Passthrough support in the project config");
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: buildTargetGroup =>
{
if (OVRProjectSetupUtils.FindComponentInScene<OVRPassthroughLayer>() == null)
{
return true;
}
var ovrManager = OVRProjectSetupUtils.FindComponentInScene<OVRManager>();
return ovrManager == null || ovrManager.isInsightPassthroughEnabled;
},
message: $"When using Passthrough in your project it's required to enable it in {nameof(OVRManager)}",
fix: buildTargetGroup =>
{
var ovrManager = OVRProjectSetupUtils.FindComponentInScene<OVRManager>();
ovrManager.isInsightPassthroughEnabled = true;
EditorUtility.SetDirty(ovrManager.gameObject);
},
fixMessage: $"Enable Passthrough in the {nameof(OVRManager)}");
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: buildTargetGroup => OVRProjectSetupCompatibilityTasks.IsTargetingARM64,
conditionalValidity: buildTargetGroup => OVRProjectConfig.CachedProjectConfig.insightPassthroughSupport !=
OVRProjectConfig.FeatureSupport.None,
message: "When enabling the Passthrough capability in your project it's required to use ARM64 as " +
"the target architecture",
fix: OVRProjectSetupCompatibilityTasks.SetARM64Target,
fixMessage: "PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64"
);
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: _ =>
{
var ovrCameraRig = OVRProjectSetupUtils.FindComponentInScene<OVRCameraRig>();
return ovrCameraRig != null &&
OVRPassthroughHelper.HasCentralCamera(ovrCameraRig) &&
OVRPassthroughHelper.IsBackgroundClear(ovrCameraRig);
},
conditionalValidity: _ =>
{
var ovrCameraRig = OVRProjectSetupUtils.FindComponentInScene<OVRCameraRig>();
return ovrCameraRig != null &&
OVRPassthroughHelper.HasCentralCamera(ovrCameraRig) &&
OVRPassthroughHelper.IsAnyPassthroughLayerUnderlay();
},
message: "When using Passthrough as an underlay it's required set the camera background to transparent",
fix: _ =>
{
var ovrCameraRig = OVRProjectSetupUtils.FindComponentInScene<OVRCameraRig>();
if (ovrCameraRig != null && OVRPassthroughHelper.HasCentralCamera(ovrCameraRig))
{
OVRPassthroughHelper.ClearBackground(ovrCameraRig);
}
},
fixMessage: "Clear background of OVRCameraRig"
);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 340956b8fb5e08e409aeab1bfc3a627d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,60 @@
/*
* 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 UnityEditor;
using UnityEngine;
[InitializeOnLoad]
internal static class OVRProjectSetupPhysicsTasks
{
static OVRProjectSetupPhysicsTasks()
{
// [Recommended] Default Contact Offset >= 0.01f
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: OVRProjectSetup.TaskGroup.Physics,
isDone: group => Physics.defaultContactOffset >= 0.01f,
message: $"Use Default Context Offset above or equal to 0.01",
fix: group => Physics.defaultContactOffset = 0.01f,
fixMessage: "Physics.defaultContactOffset = 0.01f"
);
// [Recommended] Sleep Threshold >= 0.005f
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: OVRProjectSetup.TaskGroup.Physics,
isDone: group => Physics.sleepThreshold >= 0.005f,
message: $"Use Sleep Threshold above or equal to 0.005",
fix: group => Physics.sleepThreshold = 0.005f,
fixMessage: "Physics.sleepThreshold = 0.005f"
);
// [Recommended] Default Solver Iterations <= 8
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: OVRProjectSetup.TaskGroup.Physics,
isDone: group => Physics.defaultSolverIterations <= 8,
message: $"Use Default Solver Iteration below or equal to 8",
fix: group => Physics.defaultSolverIterations = 8,
fixMessage: "Physics.defaultSolverIterations = 8"
);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8f88d78901e142de81bcf89db9d8499b
timeCreated: 1664783258

View File

@ -0,0 +1,91 @@
/*
* 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 UnityEditor;
using UnityEngine;
[InitializeOnLoad]
internal static class OVRProjectSetupQualityTasks
{
private static readonly int RecommendedPixelLightCountAndroid = 1;
private static readonly int RecommendedPixelLightCountStandalone = 3;
private static int GetRecommendedPixelLightCount(BuildTargetGroup buildTargetGroup)
=> buildTargetGroup == BuildTargetGroup.Standalone
? RecommendedPixelLightCountStandalone
: RecommendedPixelLightCountAndroid;
static OVRProjectSetupQualityTasks()
{
var taskGroup = OVRProjectSetup.TaskGroup.Quality;
// [Recommended] Set Pixel Light Count
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: taskGroup,
isDone: buildTargetGroup =>
QualitySettings.pixelLightCount <= GetRecommendedPixelLightCount(buildTargetGroup),
conditionalMessage: buildTargetGroup =>
$"Set maximum pixel lights count to {GetRecommendedPixelLightCount(buildTargetGroup)}",
fix: buildTargetGroup => QualitySettings.pixelLightCount = GetRecommendedPixelLightCount(buildTargetGroup),
conditionalFixMessage: buildTargetGroup =>
$"QualitySettings.pixelLightCount = {GetRecommendedPixelLightCount(buildTargetGroup)}"
);
// [Recommended] Set Texture Quality to Full Res
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: taskGroup,
message: "Set Texture Quality to Full Res",
#if UNITY_2022_2_OR_NEWER // masterTextureLimit has become obsolete with 2022.2
isDone: buildTargetGroup => QualitySettings.globalTextureMipmapLimit == 0,
fix: buildTargetGroup => QualitySettings.globalTextureMipmapLimit = 0,
fixMessage: "QualitySettings.globalTextureMipmapLimit = 0"
#else
isDone: buildTargetGroup => QualitySettings.masterTextureLimit == 0,
fix: buildTargetGroup => QualitySettings.masterTextureLimit = 0,
fixMessage: "QualitySettings.masterTextureLimit = 0"
#endif
);
// [Recommended] Enable Anisotropic Filtering
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: taskGroup,
isDone: buildTargetGroup => QualitySettings.anisotropicFiltering == AnisotropicFiltering.Enable,
message: "Enable Anisotropic Filtering on a per-texture basis",
fix: buildTargetGroup => QualitySettings.anisotropicFiltering = AnisotropicFiltering.Enable,
fixMessage: "QualitySettings.anisotropicFiltering = AnisotropicFiltering.Enable"
);
// Texture compression : Use ASTC
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: taskGroup,
platform: BuildTargetGroup.Android,
isDone: group => EditorUserBuildSettings.androidBuildSubtarget == MobileTextureSubtarget.ASTC ||
EditorUserBuildSettings.androidBuildSubtarget == MobileTextureSubtarget.ETC2,
message: "Optimize Texture Compression : For GPU performance, please use ETC2. In some cases, " +
"ASTC may produce better visuals and is also a viable solution",
fix: group => EditorUserBuildSettings.androidBuildSubtarget = MobileTextureSubtarget.ETC2,
fixMessage: "EditorUserBuildSettings.androidBuildSubtarget = MobileTextureSubtarget.ETC2"
);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a9f06298f32b7b54985a5a7464381e8d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,368 @@
/*
* 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.Linq;
using UnityEditor;
using UnityEditor.Rendering;
using UnityEngine;
using UnityEngine.Rendering;
#if USING_URP
using UnityEngine.Rendering.Universal;
#endif
[InitializeOnLoad]
internal static class OVRProjectSetupRenderingTasks
{
#if USING_XR_SDK_OCULUS
private static Unity.XR.Oculus.OculusSettings OculusSettings
{
get
{
UnityEditor.EditorBuildSettings.TryGetConfigObject<Unity.XR.Oculus.OculusSettings>(
"Unity.XR.Oculus.Settings", out var settings);
return settings;
}
}
#endif
#if USING_URP && UNITY_2022_2_OR_NEWER
// Call action for all UniversalRendererData being used, return true if all the return value of action is true
private static bool ForEachRendererData(Func<UniversalRendererData, bool> action)
{
var ret = true;
var pipelineAssets = new System.Collections.Generic.List<RenderPipelineAsset>();
QualitySettings.GetAllRenderPipelineAssetsForPlatform("Android", ref pipelineAssets);
foreach (var pipelineAsset in pipelineAssets)
{
var urpPipelineAsset = pipelineAsset as UniversalRenderPipelineAsset;
// If using URP pipeline
if (urpPipelineAsset)
{
var path = AssetDatabase.GetAssetPath(urpPipelineAsset);
var dependency = AssetDatabase.GetDependencies(path);
for (int i = 0; i < dependency.Length; i++)
{
// Try to read the dependency as UniversalRendererData
if (AssetDatabase.GetMainAssetTypeAtPath(dependency[i]) != typeof(UniversalRendererData))
continue;
UniversalRendererData renderData =
(UniversalRendererData)AssetDatabase.LoadAssetAtPath(dependency[i],
typeof(UniversalRendererData));
if (renderData)
{
ret = ret && action(renderData);
}
if (!ret)
{
break;
}
}
}
}
return ret;
}
#endif
private static GraphicsDeviceType[] GetGraphicsAPIs(BuildTargetGroup buildTargetGroup)
{
var buildTarget = buildTargetGroup.GetBuildTarget();
if (PlayerSettings.GetUseDefaultGraphicsAPIs(buildTarget))
{
return Array.Empty<GraphicsDeviceType>();
}
// Recommends OpenGL ES 3 or Vulkan
return PlayerSettings.GetGraphicsAPIs(buildTarget);
}
static OVRProjectSetupRenderingTasks()
{
const OVRProjectSetup.TaskGroup targetGroup = OVRProjectSetup.TaskGroup.Rendering;
//[Required] Set the color space to linear
OVRProjectSetup.AddTask(
conditionalLevel: buildTargetGroup =>
OVRProjectSetupUtils.IsPackageInstalled(OVRProjectSetupXRTasks.UnityXRPackage)
? OVRProjectSetup.TaskLevel.Required
: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
isDone: buildTargetGroup => PlayerSettings.colorSpace == ColorSpace.Linear,
message: "Color Space is required to be Linear",
fix: buildTargetGroup => PlayerSettings.colorSpace = ColorSpace.Linear,
fixMessage: "PlayerSettings.colorSpace = ColorSpace.Linear"
);
#if USING_XR_SDK_OCULUS && OCULUS_XR_EYE_TRACKED_FOVEATED_RENDERING && UNITY_2021_3_OR_NEWER
//[Required] Use Vulkan and IL2CPP/ARM64 when using ETFR
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: targetGroup,
isDone: buildTargetGroup =>
{
var useIL2CPP = PlayerSettings.GetScriptingBackend(buildTargetGroup) == ScriptingImplementation.IL2CPP;
var useARM64 = PlayerSettings.Android.targetArchitectures == AndroidArchitecture.ARM64;
var useVK = GetGraphicsAPIs(buildTargetGroup).Any(item => item == GraphicsDeviceType.Vulkan);
return useVK && useARM64 && useIL2CPP;
},
message: "Need to use Vulkan for Graphics APIs, IL2CPP for scripting backend, and ARM64 for target architectures when using eye-tracked foveated rendering",
fix: buildTargetGroup =>
{
var buildTarget = buildTargetGroup.GetBuildTarget();
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64;
PlayerSettings.SetScriptingBackend(buildTargetGroup, ScriptingImplementation.IL2CPP);
PlayerSettings.SetGraphicsAPIs(buildTarget, new[] { GraphicsDeviceType.Vulkan });
},
fixMessage: "Set target architectures to ARM64, scripting backend to IL2CPP, and Graphics APIs to Vulkan for this build.",
conditionalValidity: buildTargetGroup => OculusSettings?.FoveatedRenderingMethod == Unity.XR.Oculus.OculusSettings.FoveationMethod.EyeTrackedFoveatedRendering
);
#endif
//[Required] Disable Graphics Jobs
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
isDone: buildTargetGroup => !PlayerSettings.graphicsJobs,
message: "Disable Graphics Jobs",
fix: buildTargetGroup => PlayerSettings.graphicsJobs = false,
fixMessage: "PlayerSettings.graphicsJobs = false"
);
//[Recommended] Set the Graphics API order for Android
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
platform: BuildTargetGroup.Android,
group: targetGroup,
isDone: buildTargetGroup =>
GetGraphicsAPIs(buildTargetGroup).Any(item =>
item == GraphicsDeviceType.OpenGLES3 || item == GraphicsDeviceType.Vulkan),
message: "Manual selection of Graphic API, favoring Vulkan (or OpenGLES3)",
fix: buildTargetGroup =>
{
var buildTarget = buildTargetGroup.GetBuildTarget();
PlayerSettings.SetUseDefaultGraphicsAPIs(buildTarget, false);
PlayerSettings.SetGraphicsAPIs(buildTarget, new[] { GraphicsDeviceType.Vulkan });
},
fixMessage: "Set Graphics APIs for this build target to Vulkan"
);
//[Required] Set the Graphics API order for Windows
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
platform: BuildTargetGroup.Standalone,
group: targetGroup,
isDone: buildTargetGroup =>
GetGraphicsAPIs(buildTargetGroup).Any(item =>
item == GraphicsDeviceType.Direct3D11),
message: "Manual selection of Graphic API, favoring Direct3D11",
fix: buildTargetGroup =>
{
var buildTarget = buildTargetGroup.GetBuildTarget();
PlayerSettings.SetUseDefaultGraphicsAPIs(buildTarget, false);
PlayerSettings.SetGraphicsAPIs(buildTarget, new[] { GraphicsDeviceType.Direct3D11 });
},
fixMessage: "Set Graphics APIs for this build target to Direct3D11"
);
//[Recommended] Enable Multithreaded Rendering
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
isDone: buildTargetGroup => PlayerSettings.MTRendering &&
(buildTargetGroup != BuildTargetGroup.Android
|| PlayerSettings.GetMobileMTRendering(buildTargetGroup)),
message: "Enable Multithreaded Rendering",
fix: buildTargetGroup =>
{
PlayerSettings.MTRendering = true;
if (buildTargetGroup == BuildTargetGroup.Android)
{
PlayerSettings.SetMobileMTRendering(buildTargetGroup, true);
}
},
conditionalFixMessage: buildTargetGroup =>
buildTargetGroup == BuildTargetGroup.Android
? "PlayerSettings.MTRendering = true and PlayerSettings.SetMobileMTRendering(buildTargetGroup, true)"
: "PlayerSettings.MTRendering = true"
);
#if USING_XR_SDK_OCULUS
//[Recommended] Select Low Overhead Mode
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
conditionalValidity: buildTargetGroup =>
GetGraphicsAPIs(buildTargetGroup).Contains(GraphicsDeviceType.OpenGLES3),
group: targetGroup,
platform: BuildTargetGroup.Android,
isDone: buildTargetGroup => OculusSettings?.LowOverheadMode ?? true,
message: "Use Low Overhead Mode",
fix: buildTargetGroup =>
{
var setting = OculusSettings;
if (setting != null)
{
setting.LowOverheadMode = true;
EditorUtility.SetDirty(setting);
}
},
fixMessage: "OculusSettings.LowOverheadMode = true"
);
//[Recommended] Enable Dash Support
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
platform: BuildTargetGroup.Standalone,
isDone: buildTargetGroup => OculusSettings?.DashSupport ?? true,
message: "Enable Dash Support",
fix: buildTargetGroup =>
{
var setting = OculusSettings;
if (setting != null)
{
setting.DashSupport = true;
EditorUtility.SetDirty(setting);
}
},
fixMessage: "OculusSettings.DashSupport = true"
);
#endif
//[Recommended] Set the Display Buffer Format to 32 bit
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
isDone: buildTargetGroup =>
PlayerSettings.use32BitDisplayBuffer,
message: "Use 32Bit Display Buffer",
fix: buildTargetGroup => PlayerSettings.use32BitDisplayBuffer = true,
fixMessage: "PlayerSettings.use32BitDisplayBuffer = true"
);
//[Recommended] Set the Rendering Path to Forward
// TODO : Support Scripted Rendering Pipeline?
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
isDone: buildTargetGroup =>
EditorGraphicsSettings.GetTierSettings(buildTargetGroup, Graphics.activeTier).renderingPath ==
RenderingPath.Forward,
message: "Use Forward Rendering Path",
fix: buildTargetGroup =>
{
var renderingTier = EditorGraphicsSettings.GetTierSettings(buildTargetGroup, Graphics.activeTier);
renderingTier.renderingPath =
RenderingPath.Forward;
EditorGraphicsSettings.SetTierSettings(buildTargetGroup, Graphics.activeTier, renderingTier);
},
fixMessage: "renderingTier.renderingPath = RenderingPath.Forward"
);
//[Recommended] Set the Stereo Rendering to Instancing
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
isDone: buildTargetGroup =>
PlayerSettings.stereoRenderingPath == StereoRenderingPath.Instancing,
message: "Use Stereo Rendering Instancing",
fix: buildTargetGroup => PlayerSettings.stereoRenderingPath = StereoRenderingPath.Instancing,
fixMessage: "PlayerSettings.stereoRenderingPath = StereoRenderingPath.Instancing"
);
#if USING_URP && UNITY_2022_2_OR_NEWER
//[Recommended] When using URP, set Intermediate texture to "Auto"
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
isDone: buildTargetGroup =>
ForEachRendererData(rd => { return rd.intermediateTextureMode == IntermediateTextureMode.Auto; }),
message: "Setting the intermate texture mode to \"Always\" might have a performance impact, it is recommended to use \"Auto\"",
fix: buildTargetGroup =>
ForEachRendererData(rd => { rd.intermediateTextureMode = IntermediateTextureMode.Auto; return true; }),
fixMessage: "Set Intermediate texture to \"Auto\""
);
//[Recommended] When using URP, disable SSAO
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Recommended,
group: targetGroup,
isDone: buildTargetGroup =>
ForEachRendererData(rd =>
{
return rd.rendererFeatures.Count == 0
|| !rd.rendererFeatures.Any(
feature => feature != null && (feature.isActive && feature.GetType().Name == "ScreenSpaceAmbientOcclusion"));
}),
message: "SSAO will have some performace impact, it is recommended to disable SSAO",
fix: buildTargetGroup =>
ForEachRendererData(rd =>
{
rd.rendererFeatures.ForEach(feature =>
{
if (feature != null && feature.GetType().Name == "ScreenSpaceAmbientOcclusion")
feature.SetActive(false);
}
);
return true;
}),
fixMessage: "Disable SSAO"
);
#endif
//[Optional] Use Non-Directional Lightmaps
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Optional,
group: targetGroup,
isDone: buildTargetGroup =>
{
return LightmapSettings.lightmaps.Length == 0 ||
LightmapSettings.lightmapsMode == LightmapsMode.NonDirectional;
},
message: "Use Non-Directional lightmaps",
fix: buildTargetGroup => LightmapSettings.lightmapsMode = LightmapsMode.NonDirectional,
fixMessage: "LightmapSettings.lightmapsMode = LightmapsMode.NonDirectional"
);
//[Optional] Disable Realtime GI
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Optional,
group: targetGroup,
isDone: buildTargetGroup => !Lightmapping.realtimeGI,
message: "Disable Realtime Global Illumination",
fix: buildTargetGroup => Lightmapping.realtimeGI = false,
fixMessage: "Lightmapping.realtimeGI = false"
);
//[Optional] GPU Skinning
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Optional,
platform: BuildTargetGroup.Android,
group: targetGroup,
isDone: buildTargetGroup => PlayerSettings.gpuSkinning,
message: "Consider using GPU Skinning if your application is CPU bound",
fix: buildTargetGroup => PlayerSettings.gpuSkinning = true,
fixMessage: "PlayerSettings.gpuSkinning = true"
);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 93a7b0b65ecd19943b6eaef8cf457167
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,47 @@
/*
* 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 UnityEditor;
[InitializeOnLoad]
internal static class OVRProjectSetupSceneTasks
{
private const OVRProjectSetup.TaskGroup Group = OVRProjectSetup.TaskGroup.Features;
static OVRProjectSetupSceneTasks()
{
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: buildTargetGroup => OVRProjectSetupUtils.FindComponentInScene<OVRSceneManager>() == null ||
OVRProjectConfig.CachedProjectConfig.anchorSupport ==
OVRProjectConfig.AnchorSupport.Enabled,
message: "When using Scene in your project it's required to enable its capability in the project config",
fix: buildTargetGroup =>
{
var projectConfig = OVRProjectConfig.CachedProjectConfig;
projectConfig.anchorSupport = OVRProjectConfig.AnchorSupport.Enabled;
OVRProjectConfig.CommitProjectConfig(projectConfig);
},
fixMessage: "Enable Anchor Support in the project config"
);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 821c95a26dbfb3f40b9c76b776d3c661
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,58 @@
/*
* 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 UnityEditor;
[InitializeOnLoad]
internal static class OVRProjectSetupVirtualKeyboard
{
private const OVRProjectSetup.TaskGroup Group = OVRProjectSetup.TaskGroup.Features;
static OVRProjectSetupVirtualKeyboard()
{
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: _ => OVRProjectSetupUtils.FindComponentInScene<OVRVirtualKeyboard>() == null ||
OVRProjectConfig.CachedProjectConfig.renderModelSupport == OVRProjectConfig.RenderModelSupport.Enabled,
message: "When using Virtual Keyboard in your project it's required to enable Render Model Support",
fix: _ =>
{
var projectConfig = OVRProjectConfig.CachedProjectConfig;
projectConfig.renderModelSupport = OVRProjectConfig.RenderModelSupport.Enabled;
OVRProjectConfig.CommitProjectConfig(projectConfig);
},
fixMessage: "Enable Render Model Support");
OVRProjectSetup.AddTask(
level: OVRProjectSetup.TaskLevel.Required,
group: Group,
isDone: _ => OVRProjectSetupUtils.FindComponentInScene<OVRVirtualKeyboard>() == null ||
OVRProjectConfig.CachedProjectConfig.virtualKeyboardSupport != OVRProjectConfig.FeatureSupport.None,
message: "When using Virtual Keyboard in your project it's required to enable its capability",
fix: _ =>
{
var projectConfig = OVRProjectConfig.CachedProjectConfig;
projectConfig.virtualKeyboardSupport = OVRProjectConfig.FeatureSupport.Supported;
OVRProjectConfig.CommitProjectConfig(projectConfig);
},
fixMessage: "Enable Virtual Keyboard Support");
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 82d658a2879ff5445a9566cdc87ed59b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,173 @@
/*
* 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.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
#if USING_XR_MANAGEMENT
using UnityEditor.XR.Management;
#endif
#if USING_XR_SDK_OCULUS
using Unity.XR.Oculus;
#endif
[InitializeOnLoad]
internal static class OVRProjectSetupXRTasks
{
internal const string OculusXRPackageName = "com.unity.xr.oculus";
internal const string XRPluginManagementPackageName = "com.unity.xr.management";
internal const string UnityXRPackage = "com.unity.xr.openxr";
private const OVRProjectSetup.TaskGroup XRTaskGroup = OVRProjectSetup.TaskGroup.Packages;
static OVRProjectSetupXRTasks()
{
OVRProjectSetup.AddTask(
conditionalValidity: buildTargetGroup => OVRProjectSetupUtils.PackageManagerListAvailable,
level: OVRProjectSetup.TaskLevel.Required,
group: XRTaskGroup,
isDone: buildTargetGroup => OVRProjectSetupUtils.IsPackageInstalled(OculusXRPackageName),
message: "The Oculus XR Plug-in package must be installed",
fix: buildTargetGroup => OVRProjectSetupUtils.InstallPackage(OculusXRPackageName),
fixMessage: $"Install {OculusXRPackageName} package"
);
OVRProjectSetup.AddTask(
conditionalValidity: buildTargetGroup => OVRProjectSetupUtils.PackageManagerListAvailable,
level: OVRProjectSetup.TaskLevel.Required,
group: XRTaskGroup,
isDone: buildTargetGroup => OVRProjectSetupUtils.IsPackageInstalled(XRPluginManagementPackageName),
message: "The XR Plug-in Management package must be installed",
fix: buildTargetGroup => OVRProjectSetupUtils.InstallPackage(XRPluginManagementPackageName),
fixMessage: $"Install {XRPluginManagementPackageName} package"
);
OVRProjectSetup.AddTask(
conditionalValidity: buildTargetGroup => OVRProjectSetupUtils.PackageManagerListAvailable,
level: OVRProjectSetup.TaskLevel.Recommended,
group: XRTaskGroup,
isDone: buildTargetGroup => !OVRProjectSetupUtils.IsPackageInstalled(UnityXRPackage),
message: "Unity's OpenXR Plugin is not recommended when using the Oculus SDK, " +
"please use Oculus XR Plug-in instead",
fix: buildTargetGroup => OVRProjectSetupUtils.UninstallPackage(UnityXRPackage),
fixMessage: $"Remove the {UnityXRPackage} package"
);
AddXrPluginManagementTasks();
}
private static void AddXrPluginManagementTasks()
{
#if USING_XR_MANAGEMENT && USING_XR_SDK_OCULUS
OVRProjectSetup.AddTask(
conditionalValidity: buildTargetGroup =>
OVRProjectSetupUtils.IsPackageInstalled(XRPluginManagementPackageName),
level: OVRProjectSetup.TaskLevel.Required,
group: XRTaskGroup,
isDone: buildTargetGroup =>
{
var settings = GetXRGeneralSettingsForBuildTarget(buildTargetGroup, false);
if (settings == null)
{
return false;
}
foreach (var loader in settings.Manager.activeLoaders)
{
if (loader as OculusLoader != null)
{
return true;
}
}
return false;
},
message: "Oculus must be added to the XR Plugin active loaders",
fix: buildTargetGroup =>
{
var settings = GetXRGeneralSettingsForBuildTarget(buildTargetGroup, true);
if (settings == null)
{
throw new OVRConfigurationTaskException("Could not find XR Plugin Manager settings");
}
var loadersList = AssetDatabase.FindAssets($"t: {nameof(OculusLoader)}")
.Select(AssetDatabase.GUIDToAssetPath)
.Select(AssetDatabase.LoadAssetAtPath<OculusLoader>).ToList();
OculusLoader oculusLoader;
if (loadersList.Count > 0)
{
oculusLoader = loadersList[0];
}
else
{
oculusLoader = ScriptableObject.CreateInstance<OculusLoader>();
AssetDatabase.CreateAsset(oculusLoader, "Assets/XR/Loaders/Oculus Loader.asset");
}
settings.Manager.TryAddLoader(oculusLoader);
},
fixMessage: "Add Oculus to the XR Plugin active loaders"
);
#endif
}
#if USING_XR_MANAGEMENT && USING_XR_SDK_OCULUS
private static UnityEngine.XR.Management.XRGeneralSettings GetXRGeneralSettingsForBuildTarget(
BuildTargetGroup buildTargetGroup, bool create)
{
var settings = XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(buildTargetGroup);
if (!create || settings != null)
{
return settings;
}
// we have to create these settings ourselves as
// long as Unity doesn't expose the internal function
// XRGeneralSettingsPerBuildTarget.GetOrCreate()
var settingsKey = UnityEngine.XR.Management.XRGeneralSettings.k_SettingsKey;
EditorBuildSettings.TryGetConfigObject<XRGeneralSettingsPerBuildTarget>(
settingsKey, out var settingsPerBuildTarget);
if (settingsPerBuildTarget == null)
{
settingsPerBuildTarget = ScriptableObject.CreateInstance<XRGeneralSettingsPerBuildTarget>();
if (!AssetDatabase.IsValidFolder("Assets/XR"))
AssetDatabase.CreateFolder("Assets", "XR");
const string assetPath = "Assets/XR/XRGeneralSettingsPerBuildTarget.asset";
AssetDatabase.CreateAsset(settingsPerBuildTarget, assetPath);
AssetDatabase.SaveAssets();
EditorBuildSettings.AddConfigObject(settingsKey, settingsPerBuildTarget, true);
}
if (!settingsPerBuildTarget.HasManagerSettingsForBuildTarget(buildTargetGroup))
{
settingsPerBuildTarget.CreateDefaultManagerSettingsForBuildTarget(buildTargetGroup);
}
return XRGeneralSettingsPerBuildTarget.XRGeneralSettingsForBuildTarget(buildTargetGroup);
}
#endif
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: beb76c27b37f99e43a27f9d2656dafc6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,270 @@
/*
* 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<BuildTargetGroup, bool> Valid { get; }
public OptionalLambdaType<BuildTargetGroup, OVRProjectSetup.TaskLevel> Level { get; }
public OptionalLambdaType<BuildTargetGroup, string> Message { get; }
public OptionalLambdaType<BuildTargetGroup, string> FixMessage { get; }
public OptionalLambdaType<BuildTargetGroup, string> URL { get; }
public OVRConfigurationTaskSourceCode SourceCode { get; set; }
private Func<BuildTargetGroup, bool> _isDone;
public Func<BuildTargetGroup, bool> IsDone
{
get => GetDoneState;
private set => _isDone = value;
}
public Action<BuildTargetGroup> FixAction { get; }
private readonly Dictionary<BuildTargetGroup, OVRProjectSetupSettingBool> _ignoreSettings =
new Dictionary<BuildTargetGroup, OVRProjectSetupSettingBool>();
private readonly Dictionary<BuildTargetGroup, bool> _isDoneCache = new Dictionary<BuildTargetGroup, bool>();
public OVRConfigurationTask(
OVRProjectSetup.TaskGroup group,
BuildTargetGroup platform,
Func<BuildTargetGroup, bool> isDone,
Action<BuildTargetGroup> fix,
OptionalLambdaType<BuildTargetGroup, OVRProjectSetup.TaskLevel> level,
OptionalLambdaType<BuildTargetGroup, string> message,
OptionalLambdaType<BuildTargetGroup, string> fixMessage,
OptionalLambdaType<BuildTargetGroup, string> url,
OptionalLambdaType<BuildTargetGroup, bool> 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<BuildTargetGroup, string>(null);
FixMessage = fixMessage ?? new OptionalLambdaTypeWithoutLambda<BuildTargetGroup, string>(null);
Valid = valid ?? new OptionalLambdaTypeWithoutLambda<BuildTargetGroup, bool>(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 " +
$"<a href=\"{ConsoleLinkHref}\">Edit > Project Settings > {OVRProjectSetupSettingsProvider.SettingsName}</a>";
}
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
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 23cf0a62a13a153468744c574d80aab8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,41 @@
/*
* 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;
public class OVRConfigurationTaskException : Exception
{
public OVRConfigurationTaskException()
{
}
public OVRConfigurationTaskException(string message)
: base(message)
{
}
public OVRConfigurationTaskException(string message, Exception inner)
: base(message, inner)
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7d5dcbd522a347fca62378e9e47b9893
timeCreated: 1664378185

View File

@ -0,0 +1,125 @@
/*
* 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 System.Linq;
using UnityEditor;
using UnityEngine;
internal class OVRConfigurationTaskRegistry
{
private static readonly List<OVRConfigurationTask> EmptyTasksList = new List<OVRConfigurationTask>(0);
private readonly Dictionary<Hash128, OVRConfigurationTask> _tasksPerUid =
new Dictionary<Hash128, OVRConfigurationTask>();
private readonly List<OVRConfigurationTask> _tasks = new List<OVRConfigurationTask>();
private List<OVRConfigurationTask> Tasks => _tasks;
public void AddTask(OVRConfigurationTask task)
{
var uid = task.Uid;
if (_tasksPerUid.ContainsKey(uid))
{
// This task is already registered
return;
}
_tasks.Add(task);
_tasksPerUid.Add(uid, task);
#if UNITY_XR_CORE_UTILS
RegisterToBuildValidator(task);
#endif
}
#if UNITY_XR_CORE_UTILS
private void RegisterToBuildValidator(OVRConfigurationTask task)
{
if (task.Platform == BuildTargetGroup.Unknown)
{
var buildTargetGroups = Enum.GetValues(typeof(BuildTargetGroup));
foreach (var buildTargetGroup in buildTargetGroups)
{
var targetGroup = (BuildTargetGroup)buildTargetGroup;
RegisterToBuildValidator(targetGroup, task);
}
}
else
{
RegisterToBuildValidator(task.Platform, task);
}
}
private void RegisterToBuildValidator(BuildTargetGroup targetGroup, OVRConfigurationTask task)
{
if (task.Level.GetValue(targetGroup) == OVRProjectSetup.TaskLevel.Optional)
{
return;
}
Unity.XR.CoreUtils.Editor.BuildValidator.AddRules(targetGroup, new []{task.ToValidationRule(task.Platform)});
}
#endif
public void RemoveTask(Hash128 uid)
{
var task = GetTask(uid);
RemoveTask(task);
}
public void RemoveTask(OVRConfigurationTask task)
{
_tasks.Remove(task);
_tasksPerUid.Remove(task.Uid);
}
public OVRConfigurationTask GetTask(Hash128 uid)
{
_tasksPerUid.TryGetValue(uid, out var task);
return task;
}
public void Clear()
{
_tasksPerUid.Clear();
_tasks.Clear();
}
internal IEnumerable<OVRConfigurationTask> GetTasks(BuildTargetGroup buildTargetGroup, bool refresh)
{
if (refresh)
{
foreach (var task in Tasks)
{
task.InvalidateCache(buildTargetGroup);
}
}
return Tasks.Where
(
task => (task.Platform == BuildTargetGroup.Unknown || task.Platform == buildTargetGroup)
&& task.Valid.GetValue(buildTargetGroup)
);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fef3c9d3bbb64a21ac221b2b3fbca1ef
timeCreated: 1662024023

View File

@ -0,0 +1,150 @@
/*
* 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 System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
internal class OVRConfigurationTaskSourceCode
{
private static Func<Object, int, bool> OpenAssetDelegate = AssetDatabase.OpenAsset;
public static void Mock()
{
OpenAssetDelegate = null;
}
public static void Unmock()
{
OpenAssetDelegate = AssetDatabase.OpenAsset;
}
private static IEnumerable<MethodInfo> _expectedMethods;
private static IEnumerable<MethodInfo> ExpectedMethods
{
get
{
if (_expectedMethods == null)
{
_expectedMethods = typeof(OVRProjectSetup).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(method => method.Name == "AddTask");
}
return _expectedMethods;
}
}
private OVRConfigurationTask _task;
private readonly StackTrace _stackTrace;
private Object _object;
private bool _processed;
public bool Valid
{
get
{
if (!_processed)
{
ProcessStackTrace();
}
return _object != null;
}
}
public int Line { get; private set; }
public string FilePath { get; private set; }
public OVRConfigurationTaskSourceCode(OVRConfigurationTask task)
{
_task = task;
_stackTrace = new StackTrace(true);
}
public void ProcessStackTrace()
{
if (FindPathAndLine(out var path, out var line))
{
path = path.Replace("\\", "/");
if (path.StartsWith(Application.dataPath))
{
FilePath = Path.Combine("Assets/", path.Substring(Application.dataPath.Length + 1));
Line = line;
_object = AssetDatabase.LoadAssetAtPath(FilePath, typeof(Object));
}
}
_processed = true;
}
public bool Open()
{
if (Valid)
{
OpenAssetDelegate?.Invoke(_object, Line);
}
OVRTelemetry.Start(OVRProjectSetupTelemetryEvent.EventTypes.GoToSource)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Uid, _task.Uid.ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.BuildTargetGroup,
BuildTargetGroup.Unknown.ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Value, Valid ? "true" : "false")
.Send();
return Valid;
}
private StackFrame FindStackFrame()
{
// Depth 2, Just before the constructor
StackFrame frame = _stackTrace.GetFrame(2);
var method = frame.GetMethod();
if (ExpectedMethods.Contains(method))
{
// Depth 3, Just before OVRProjectSetup AddTask
frame = _stackTrace.GetFrame(3);
}
return frame;
}
private bool FindPathAndLine(out string path, out int line)
{
var frame = FindStackFrame();
if (frame == null)
{
path = null;
line = -1;
return false;
}
path = frame.GetFileName();
line = frame.GetFileLineNumber();
return true;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b25802328957400cb1180db46a429f8b
timeCreated: 1665496546

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ae567593b4a0438c80fd037782a57588
timeCreated: 1663596823

View File

@ -0,0 +1,89 @@
/*
* 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.Collections.Generic;
using UnityEditor;
using System;
using System.Linq;
using UnityEngine;
internal class OVRConfigurationTaskFixer : OVRConfigurationTaskProcessor
{
public override int AllocatedTimeInMs => 10;
public override ProcessorType Type => ProcessorType.Fixer;
protected override Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> OpenTasksFilter =>
(Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>>)(tasksToFilter => tasksToFilter
.Where(task => task.FixAction != null
&& !task.IsDone(BuildTargetGroup)
&& !task.IsIgnored(BuildTargetGroup))
.ToList());
private const int LoopExitCount = 4;
private bool _hasFixedSome = false;
private int _counter = LoopExitCount;
public OVRConfigurationTaskFixer(
OVRConfigurationTaskRegistry registry,
BuildTargetGroup buildTargetGroup,
Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> filter,
OVRProjectSetup.LogMessages logMessages,
bool blocking,
Action<OVRConfigurationTaskProcessor> onCompleted)
: base(registry, buildTargetGroup, filter, logMessages, blocking, onCompleted)
{
}
protected override void ProcessTask(OVRConfigurationTask task)
{
_hasFixedSome |= task.Fix(BuildTargetGroup);
}
protected override void PrepareTasks()
{
_hasFixedSome = false;
base.PrepareTasks();
}
protected override void Validate()
{
_counter--;
if (_counter <= 0)
{
Debug.LogWarning("[Oculus Settings] Fixing Tasks has exited after too many iterations. " +
"(There might be some contradictory rules leading to a loop)");
return;
}
if (!_hasFixedSome)
{
return;
}
// Preparing a new Run
PrepareTasks();
if (Blocking)
{
Update();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6e1fe0a245064a44b8b080a115da8c1d
timeCreated: 1663596864

View File

@ -0,0 +1,127 @@
/*
* 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.Collections.Generic;
using UnityEditor;
using System;
using System.Linq;
internal abstract class OVRConfigurationTaskProcessor
{
public enum ProcessorType
{
Updater,
Fixer
}
public virtual int AllocatedTimeInMs => 10;
protected abstract void ProcessTask(OVRConfigurationTask task);
public abstract ProcessorType Type { get; }
private BuildTargetGroup _buildTargetGroup;
private OVRProjectSetup.LogMessages _logMessages;
private readonly OVRConfigurationTaskRegistry _registry;
private Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> _filter;
protected abstract Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> OpenTasksFilter { get; }
private List<OVRConfigurationTask> _tasks;
private IEnumerator<OVRConfigurationTask> _enumerator;
private int _startTime;
public bool Blocking { get; set; }
public event Action<OVRConfigurationTaskProcessor> OnComplete;
public BuildTargetGroup BuildTargetGroup => _buildTargetGroup;
public OVRProjectSetup.LogMessages LogMessages => _logMessages;
// Status
public bool Started => _startTime != -1;
public bool Processing => _enumerator != null;
public bool Completed => Started && (_enumerator == null || _enumerator.Current == null);
public List<OVRConfigurationTask> Tasks => _tasks;
protected OVRConfigurationTaskProcessor(OVRConfigurationTaskRegistry registry, BuildTargetGroup buildTargetGroup,
Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> filter,
OVRProjectSetup.LogMessages logMessages,
bool blocking,
Action<OVRConfigurationTaskProcessor> onCompleted)
{
_registry = registry;
_enumerator = null;
_buildTargetGroup = buildTargetGroup;
_logMessages = logMessages;
Blocking = blocking;
_filter = filter;
_startTime = -1;
OnComplete += onCompleted;
}
protected virtual void PrepareTasks()
{
// Get all the tasks from the Setup Tool
var tasks = _registry.GetTasks(_buildTargetGroup, true);
// Apply the caller-provided filter
_tasks = _filter != null ? _filter(tasks) : tasks.ToList();
// When not forced, apply the OpenTaskFilter as well
_tasks = (OpenTasksFilter != null) ? OpenTasksFilter(_tasks) : _tasks;
// Prepare the Enumerator
_enumerator = _tasks.GetEnumerator();
_enumerator.MoveNext();
}
public virtual void OnRequested()
{
}
public virtual void Start()
{
PrepareTasks();
_startTime = Environment.TickCount;
}
public void Update()
{
var updateTime = Environment.TickCount;
var currentTime = updateTime;
while ((Blocking || (currentTime - updateTime < AllocatedTimeInMs)) && _enumerator?.Current != null)
{
ProcessTask(_enumerator.Current);
currentTime = Environment.TickCount;
_enumerator.MoveNext();
}
if (Completed)
{
Validate();
}
}
protected virtual void Validate()
{
}
public virtual void Complete()
{
_enumerator = null;
OnComplete?.Invoke(this);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: da7a8c3cbcb14aba8b02a89bc05e136f
timeCreated: 1663596850

View File

@ -0,0 +1,149 @@
/*
* 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;
internal class OVRConfigurationTaskProcessorQueue
{
public event Action<OVRConfigurationTaskProcessor> OnProcessorCompleted;
private readonly Queue<OVRConfigurationTaskProcessor> _queue = new Queue<OVRConfigurationTaskProcessor>();
public bool Busy => _queue.Count > 0;
public bool Blocked => Busy && _queue.Peek().Blocking;
public bool BlockedBy(OVRConfigurationTaskProcessor.ProcessorType processorType)
{
foreach (var processor in _queue)
{
if (processor.Type == processorType && processor.Blocking)
{
return true;
}
}
return false;
}
public bool BusyWith(OVRConfigurationTaskProcessor.ProcessorType processorType)
{
foreach (var processor in _queue)
{
if (processor.Type == processorType)
{
return true;
}
}
return false;
}
public void Request(OVRConfigurationTaskProcessor processor)
{
if (!OVRProjectSetup.Enabled.Value)
{
return;
}
Enqueue(processor);
}
private void Enqueue(OVRConfigurationTaskProcessor processor)
{
if (!Busy)
{
// If was empty, then register to editor update
EditorApplication.update += Update;
}
// Enqueue
_queue.Enqueue(processor);
processor.OnRequested();
if (processor.Blocking)
{
// In the case where the newly added processor is blocking
// we'll make all the previously queued processor blocking as well
foreach (var otherProcessor in _queue)
{
otherProcessor.Blocking = true;
}
// Force an update, this will be The blocking update
Update();
}
}
private void Dequeue(OVRConfigurationTaskProcessor processor)
{
// We should only dequeue the current processor
if (processor != _queue.Peek())
{
return;
}
// Dequeue
_queue.Dequeue();
if (!Busy)
{
// Now that it is empty, unregister to editor update
EditorApplication.update -= Update;
}
// Trigger specific callbacks
processor.Complete();
// Trigger global callbacks
OnProcessorCompleted?.Invoke(processor);
}
private void Update()
{
var processor = _queue.Count > 0 ? _queue.Peek() : null;
while (processor != null)
{
if (!processor.Started)
{
processor.Start();
}
processor.Update();
if (processor.Completed)
{
Dequeue(processor);
// Move to the next processor
processor = _queue.Count > 0 ? _queue.Peek() : null;
}
if (!(processor?.Blocking ?? false))
{
// Is the processor is not blocking, we can stop the update until the next update call
processor = null;
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 97ad6b63e1e34a329c0b5b3a69e7d8e7
timeCreated: 1663597510

View File

@ -0,0 +1,85 @@
/*
* 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.Collections.Generic;
using UnityEditor;
using System;
using System.Linq;
internal class OVRConfigurationTaskUpdater : OVRConfigurationTaskProcessor
{
public override int AllocatedTimeInMs => 10;
private readonly OVRConfigurationTaskUpdaterSummary _summary;
protected override Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> OpenTasksFilter =>
(Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>>)(tasksToFilter => tasksToFilter
.Where(task => !task.IsIgnored(BuildTargetGroup))
.ToList());
public override ProcessorType Type => ProcessorType.Updater;
public OVRConfigurationTaskUpdaterSummary Summary => _summary;
public OVRConfigurationTaskUpdater(
OVRConfigurationTaskRegistry registry,
BuildTargetGroup buildTargetGroup,
Func<IEnumerable<OVRConfigurationTask>, List<OVRConfigurationTask>> filter,
OVRProjectSetup.LogMessages logMessages,
bool blocking,
Action<OVRConfigurationTaskProcessor> onCompleted)
: base(registry, buildTargetGroup, filter, logMessages, blocking, onCompleted)
{
_summary = new OVRConfigurationTaskUpdaterSummary(BuildTargetGroup);
}
protected override void PrepareTasks()
{
_summary.Reset();
base.PrepareTasks();
}
protected override void ProcessTask(OVRConfigurationTask task)
{
var changedState = task.UpdateAndGetStateChanged(BuildTargetGroup);
Summary.AddTask(task, changedState);
if (task.IsDone(BuildTargetGroup))
{
return;
}
if (LogMessages == OVRProjectSetup.LogMessages.All
|| (LogMessages == OVRProjectSetup.LogMessages.Changed && changedState))
{
task.LogMessage(BuildTargetGroup);
}
}
public override void Complete()
{
Summary.Validate();
if (LogMessages >= OVRProjectSetup.LogMessages.Summary)
{
Summary.Log();
}
base.Complete();
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 36d246eb26384ec88c5d849668cf29a7
timeCreated: 1663591461

View File

@ -0,0 +1,246 @@
/*
* 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.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
internal class OVRConfigurationTaskUpdaterSummary
{
private readonly List<OVRConfigurationTask> _doneTasks;
private readonly List<OVRConfigurationTask> _outstandingTasks;
private readonly Dictionary<OVRProjectSetup.TaskLevel, List<OVRConfigurationTask>> _outstandingTasksPerLevel;
private bool HasNewOutstandingTasks { get; set; }
private bool HasAnyChange { get; set; }
public bool HasAvailableFixes => _outstandingTasks.Count > 0;
public bool HasFixes(OVRProjectSetup.TaskLevel taskLevel) => _outstandingTasksPerLevel[taskLevel].Count > 0;
public int GetNumberOfFixes(OVRProjectSetup.TaskLevel taskLevel) => _outstandingTasksPerLevel[taskLevel].Count;
public int GetTotalNumberOfFixes() => _outstandingTasks.Count;
private readonly BuildTargetGroup _buildTargetGroup;
public BuildTargetGroup BuildTargetGroup => _buildTargetGroup;
public OVRConfigurationTaskUpdaterSummary(BuildTargetGroup buildTargetGroup)
{
_buildTargetGroup = buildTargetGroup;
_doneTasks = new List<OVRConfigurationTask>();
_outstandingTasks = new List<OVRConfigurationTask>();
_outstandingTasksPerLevel = new Dictionary<OVRProjectSetup.TaskLevel, List<OVRConfigurationTask>>();
for (var i = OVRProjectSetup.TaskLevel.Required; i >= OVRProjectSetup.TaskLevel.Optional; i--)
{
_outstandingTasksPerLevel.Add(i, new List<OVRConfigurationTask>());
}
}
public void Reset()
{
_doneTasks.Clear();
_outstandingTasks.Clear();
for (var i = OVRProjectSetup.TaskLevel.Required; i >= OVRProjectSetup.TaskLevel.Optional; i--)
{
_outstandingTasksPerLevel[i].Clear();
}
HasNewOutstandingTasks = false;
HasAnyChange = false;
}
public void AddTask(OVRConfigurationTask task, bool changedState)
{
if (task.IsDone(_buildTargetGroup))
{
_doneTasks.Add(task);
}
else
{
_outstandingTasks.Add(task);
_outstandingTasksPerLevel[task.Level.GetValue(_buildTargetGroup)].Add(task);
HasNewOutstandingTasks |= changedState;
}
HasAnyChange |= changedState;
}
public void Validate()
{
if (HasAnyChange)
{
LogEvent();
}
var interactionFlowEvent = OVRProjectSetupSettingsProvider.InteractionFlowEvent;
if (interactionFlowEvent == null)
{
if (GetTotalNumberOfFixes() > 0)
{
interactionFlowEvent = OVRTelemetry
.Start(OVRProjectSetupTelemetryEvent.EventTypes.InteractionFlow)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Level,
HighestFixLevel?.ToString() ?? "None")
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Count,
GetNumberOfFixes(HighestFixLevel ?? OVRProjectSetup.TaskLevel.Required).ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Level,
HighestFixLevel?.ToString() ?? "None")
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Value,
GetTotalNumberOfFixes().ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.BuildTargetGroup,
BuildTargetGroup.ToString());
OVRProjectSetupSettingsProvider.InteractionFlowEvent = interactionFlowEvent;
}
}
else
{
interactionFlowEvent = interactionFlowEvent?.AddAnnotation(
OVRProjectSetupTelemetryEvent.AnnotationTypes.BuildTargetGroupAfter,
BuildTargetGroup.ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.ValueAfter,
GetTotalNumberOfFixes().ToString());
OVRProjectSetupSettingsProvider.InteractionFlowEvent = interactionFlowEvent;
}
}
public OVRProjectSetup.TaskLevel? HighestFixLevel
{
get
{
for (var i = OVRProjectSetup.TaskLevel.Required; i >= OVRProjectSetup.TaskLevel.Optional; i--)
{
if (HasFixes(i))
{
return i;
}
}
return null;
}
}
public string GenerateReport(string outputPath = null, string fileName = null)
{
var sortedTasks = _outstandingTasks.Concat(_doneTasks);
return OVRProjectSetupReport.GenerateJson(
sortedTasks,
_buildTargetGroup,
outputPath,
fileName
);
}
public string ComputeNoticeMessage()
{
var highestLevel = HighestFixLevel;
var level = highestLevel ?? OVRProjectSetup.TaskLevel.Optional;
var count = GetNumberOfFixes(level);
if (count == 0)
{
return $"Oculus-Ready for {_buildTargetGroup}";
}
else
{
var message = GetLogMessage(level, count);
return message;
}
}
public string ComputeLogMessage()
{
var highestLevel = HighestFixLevel;
var level = highestLevel ?? OVRProjectSetup.TaskLevel.Optional;
var count = GetNumberOfFixes(level);
var message = GetFullLogMessage(level, count);
return message;
}
public void LogEvent()
{
OVRTelemetry.Start(OVRProjectSetupTelemetryEvent.EventTypes.Summary)
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Level, HighestFixLevel?.ToString() ?? "None")
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Count,
GetNumberOfFixes(HighestFixLevel ?? OVRProjectSetup.TaskLevel.Required).ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.BuildTargetGroup, BuildTargetGroup.ToString())
.AddAnnotation(OVRProjectSetupTelemetryEvent.AnnotationTypes.Value, GetTotalNumberOfFixes().ToString())
.Send();
}
public void Log()
{
if (!HasNewOutstandingTasks)
{
return;
}
var highestLevel = HighestFixLevel;
var message = ComputeLogMessage();
switch (highestLevel)
{
case OVRProjectSetup.TaskLevel.Optional:
{
Debug.Log(message);
}
break;
case OVRProjectSetup.TaskLevel.Recommended:
{
Debug.LogWarning(message);
}
break;
case OVRProjectSetup.TaskLevel.Required:
{
if (OVRProjectSetup.RequiredThrowErrors.Value)
{
Debug.LogError(message);
}
else
{
Debug.LogWarning(message);
}
}
break;
}
}
private static string GetLogMessage(OVRProjectSetup.TaskLevel level, int count)
{
switch (count)
{
case 0:
return $"There are no outstanding {level.ToString()} fixes.";
case 1:
return $"There is 1 outstanding {level.ToString()} fix.";
default:
return $"There are {count} outstanding {level.ToString()} fixes.";
}
}
internal static string GetFullLogMessage(OVRProjectSetup.TaskLevel level, int count)
{
return
$"[Oculus Settings] {GetLogMessage(level, count)}\nFor more information, go to <a href=\"{OVRConfigurationTask.ConsoleLinkHref}\">Edit > Project Settings > {OVRProjectSetupSettingsProvider.SettingsName}</a>";
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c1baa7891a0f4c63ad746d7e1b35faef
timeCreated: 1660745160

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 36ee7ddd85174b59ad43e9bdb151fedd
timeCreated: 1666883993

View File

@ -0,0 +1,61 @@
/*
* 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 static OVRTelemetry;
internal static class OVRProjectSetupTelemetryEvent
{
public static class EventTypes
{
// Attention : Need to be kept in sync with QPL Event Ids
public const int Fix = 163058027;
public const int Option = 163058846;
public const int GoToSource = 163056520;
public const int Summary = 163063879;
public const int Open = 163056010;
public const int Close = 163056958;
public const int InteractionFlow = 163069594;
}
public static class AnnotationTypes
{
public const string Uid = "Uid";
public const string Level = "Level";
public const string Type = "Type";
public const string Value = "Value";
public const string BuildTargetGroup = "BuildTargetGroup";
public const string Group = "Group";
public const string Blocking = "Blocking";
public const string Count = "Count";
public const string Origin = "Origin";
public const string TimeSpent = "TimeSpent";
public const string Interaction = "Interaction";
public const string ValueAfter = "ValueAfter";
public const string BuildTargetGroupAfter = "BuildTargetGroupAfter";
}
public static class MarkerPoints
{
public static readonly MarkerPoint Process = new MarkerPoint("Process");
public static readonly MarkerPoint Open = new MarkerPoint("Open");
public static readonly MarkerPoint Interact = new MarkerPoint("Interact");
public static readonly MarkerPoint Close = new MarkerPoint("Close");
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e3d69e61ddc14e19ac7aca4bd186f5e1
timeCreated: 1666884008

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 00c568f16a61407fa12c2e7e67a29f67
timeCreated: 1663063024

View File

@ -0,0 +1,85 @@
/*
* 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 System.Reflection;
using UnityEditor;
[InitializeOnLoad]
internal static class ConsoleLinkEventHandler
{
public static event Action<Dictionary<string, string>> OnConsoleLink;
#if UNITY_2021_2_OR_NEWER
// Much simpler code in 2021 as the API became public
static ConsoleLinkEventHandler()
{
EditorGUI.hyperLinkClicked += OnConsoleLinkInternal;
}
private static void OnConsoleLinkInternal(EditorWindow window, HyperLinkClickedEventArgs arguments)
{
OnConsoleLink?.Invoke(arguments.hyperLinkData);
}
#else
// Using reflection to hack into the internal hyperLinkClicked event before 2021
private static PropertyInfo _parametersProperty;
static ConsoleLinkEventHandler()
{
var evt = typeof(EditorGUI).GetEvent("hyperLinkClicked", BindingFlags.Static | BindingFlags.NonPublic);
if (evt != null)
{
var method = typeof(ConsoleLinkEventHandler).GetMethod("OnConsoleLinkInternal",
BindingFlags.Static | BindingFlags.NonPublic);
if (method != null)
{
var handler = Delegate.CreateDelegate(evt.EventHandlerType, method);
evt.AddMethod.Invoke(null, new object[] { handler });
}
}
}
private static bool InitialiseParametersProperty(EventArgs arguments)
{
if (_parametersProperty == null)
{
_parametersProperty = arguments.GetType()
.GetProperty("hyperlinkInfos", BindingFlags.Instance | BindingFlags.Public);
}
return _parametersProperty != null;
}
private static void OnConsoleLinkInternal(object sender, EventArgs arguments)
{
if (!InitialiseParametersProperty(arguments))
{
return;
}
if (_parametersProperty.GetValue(arguments) is Dictionary<string, string> argumentsAsDictionary)
{
OnConsoleLink?.Invoke(argumentsAsDictionary);
}
}
#endif
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2508c18b7ce0d9a489afb99ff7088bd7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,127 @@
/*
* 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;
internal abstract class OptionalLambdaType<TLambdaArgumentType, TValueType>
{
public static OptionalLambdaType<TLambdaArgumentType, TValueType> Create(TValueType value,
Func<TLambdaArgumentType, TValueType> lambda, bool allowCache)
{
OptionalLambdaType<TLambdaArgumentType, TValueType> optionalLambdaType = null;
if (lambda != null)
{
if (allowCache)
{
optionalLambdaType = new OptionalLambdaTypeWithCachedLambda<TLambdaArgumentType, TValueType>(lambda);
}
else
{
optionalLambdaType = new OptionalLambdaTypeWithLambda<TLambdaArgumentType, TValueType>(lambda);
}
}
else
{
optionalLambdaType = new OptionalLambdaTypeWithoutLambda<TLambdaArgumentType, TValueType>(value);
}
return optionalLambdaType;
}
public static implicit operator OptionalLambdaType<TLambdaArgumentType, TValueType>(TValueType value)
{
var optionalLambdaType = new OptionalLambdaTypeWithoutLambda<TLambdaArgumentType, TValueType>(value);
return optionalLambdaType;
}
public static implicit operator OptionalLambdaType<TLambdaArgumentType, TValueType>(
Func<TLambdaArgumentType, TValueType> lambda)
{
var optionalLambdaType = new OptionalLambdaTypeWithLambda<TLambdaArgumentType, TValueType>(lambda);
return optionalLambdaType;
}
public abstract bool Valid { get; }
public abstract TValueType GetValue(TLambdaArgumentType arg);
public abstract TValueType Default { get; }
public virtual void InvalidateCache(TLambdaArgumentType arg)
{
}
}
internal class OptionalLambdaTypeWithoutLambda<TLambdaArgumentType, TValueType>
: OptionalLambdaType<TLambdaArgumentType, TValueType>
{
private readonly TValueType _value;
public OptionalLambdaTypeWithoutLambda(TValueType value)
{
_value = value;
}
public override TValueType GetValue(TLambdaArgumentType arg) => _value;
public override TValueType Default => _value;
public override bool Valid => _value != null;
}
internal class OptionalLambdaTypeWithLambda<TLambdaArgumentType, TValueType>
: OptionalLambdaType<TLambdaArgumentType, TValueType>
{
protected readonly Func<TLambdaArgumentType, TValueType> Lambda;
public OptionalLambdaTypeWithLambda(Func<TLambdaArgumentType, TValueType> lambda)
{
Lambda = lambda;
}
public override TValueType GetValue(TLambdaArgumentType arg) => Lambda.Invoke(arg);
public override TValueType Default => Lambda.Invoke(default(TLambdaArgumentType));
public override bool Valid => Lambda != null && Default != null;
}
internal class OptionalLambdaTypeWithCachedLambda<TLambdaArgumentType, TValueType>
: OptionalLambdaTypeWithLambda<TLambdaArgumentType, TValueType>
{
private readonly Dictionary<TLambdaArgumentType, TValueType> _cachedValues =
new Dictionary<TLambdaArgumentType, TValueType>();
public OptionalLambdaTypeWithCachedLambda(Func<TLambdaArgumentType, TValueType> lambda) : base(lambda)
{
}
public override TValueType GetValue(TLambdaArgumentType arg)
{
if (!_cachedValues.TryGetValue(arg, out var value))
{
value = base.GetValue(arg);
_cachedValues.Add(arg, value);
}
return value;
}
public override void InvalidateCache(TLambdaArgumentType arg)
{
_cachedValues.Remove(arg);
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eeb765bc919545b893b0c57629625f14
timeCreated: 1662026667

View File

@ -0,0 +1,62 @@
/*
* 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 UnityEngine;
[Serializable]
public class SerializableDictionary<TKey, TValue> : Dictionary<TKey, TValue>, ISerializationCallbackReceiver
{
[SerializeField]
private List<TKey> keys = new List<TKey>();
[SerializeField]
private List<TValue> values = new List<TValue>();
// save the dictionary to lists
public void OnBeforeSerialize()
{
keys.Clear();
values.Clear();
foreach (var pair in this)
{
keys.Add(pair.Key);
values.Add(pair.Value);
}
}
// load dictionary from lists
public void OnAfterDeserialize()
{
this.Clear();
if (keys.Count != values.Count)
{
throw new System.Exception(string.Format(
"there are {0} keys and {1} values after deserialization. Make sure that both key and value types are serializable."));
}
for (var i = 0; i < keys.Count; i++)
{
this.Add(keys[i], values[i]);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 65ebc4746fe6453ba8e7d3433ba52579
timeCreated: 1663063037