add ready player me POC

This commit is contained in:
2024-11-22 07:08:52 +02:00
parent 855639487b
commit 7c4e48f388
1033 changed files with 224048 additions and 28 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3cd7b15d18039474489020dd9d3daf34
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace ReadyPlayerMe.AvatarCreator.Editor
{
[CustomPropertyDrawer(typeof(AssetTypeFilterAttribute))]
public class AssetTypeFilterDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var assetTypeAttribute = attribute as AssetTypeFilterAttribute;
if (property.propertyType == SerializedPropertyType.Enum)
{
EditorGUI.BeginProperty(position, label, property);
EditorGUI.BeginChangeCheck();
// Get the current enum value
var currentEnumValue = (AssetType) property.enumValueIndex;
var filteredEnumNames = new List<string>();
foreach (var enumName in Enum.GetNames(typeof(AssetType)))
{
var enumFieldInfo = typeof(AssetType).GetField(enumName);
var enumAttribute = (AssetTypeFilterAttribute) Attribute.GetCustomAttribute(enumFieldInfo, typeof(AssetTypeFilterAttribute));
if (enumAttribute == null) continue;
var filter = (AssetFilter) Enum.Parse(typeof(AssetFilter), enumAttribute.filter.ToString());
if (filter == assetTypeAttribute?.filter)
{
filteredEnumNames.Add(enumName);
}
}
// Display the dropdown with filtered enum values
var newIndex = EditorGUI.Popup(position, label.text, Array.IndexOf(filteredEnumNames.ToArray(), currentEnumValue.ToString()), filteredEnumNames.ToArray());
// Set the new enum value if it has changed
if (EditorGUI.EndChangeCheck())
{
property.enumValueIndex = (int) Enum.Parse(typeof(AssetType), filteredEnumNames[newIndex]);
}
EditorGUI.EndProperty();
}
else
{
EditorGUI.LabelField(position, label.text, "Use AssetType with Enum.");
}
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 6add29e0a6c64d6786c6742dfbd87acf
timeCreated: 1702392584
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/AvatarCreator/AssetTypeFilterDrawer.cs
uploadId: 704624
@@ -0,0 +1,19 @@
{
"name": "ReadyPlayerMe.AvatarCreator.Editor",
"rootNamespace": "",
"references": [
"ReadyPlayerMe.Core",
"ReadyPlayerMe.AvatarCreator"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 0ed01c010d356f94b99818818dbd9430
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/AvatarCreator/ReadyPlayerMe.AvatarCreator.Editor.asmdef
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 17b21c922120b25458033294675f03ec
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 15d9bb0049cd8b245900c3f74fc99cb0
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,127 @@
fileFormatVersion: 2
guid: 97cb8e496ac634f4ba4c0a1bb899c8da
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
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
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: -1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
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: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 1024
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 1024
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 1024
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: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Resources/Banner.png
uploadId: 704624
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

@@ -0,0 +1,139 @@
fileFormatVersion: 2
guid: 38a8827f446904c4c802c5b7850e3ff0
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 11
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
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: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
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: 8
textureShape: 1
singleChannelComponent: 0
flipbookRows: 1
flipbookColumns: 1
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
ignorePngGamma: 0
applyGammaDecoding: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: Standalone
maxTextureSize: 32
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: 32
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 0
- serializedVersion: 3
buildTarget: WebGL
maxTextureSize: 32
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: 5e97eb03825dee720800000000000000
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Resources/rpm_error_icon.png
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 05e3bb89ec0ad464c9a480276df7c651
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ac1c518000284e8ea25dfdd1284e0f16
timeCreated: 1657013631
@@ -0,0 +1,301 @@
using System;
using System.Collections.Generic;
using ReadyPlayerMe.Core.Editor;
using UnityEditor;
using UnityEngine;
using static ReadyPlayerMe.Core.Analytics.Constants;
namespace ReadyPlayerMe.Core.Analytics
{
public class AmplitudeEditorLogger : IAnalyticsEditorLogger
{
private const string SDK_TARGET = "Unity";
private readonly Dictionary<HelpSubject, string> helpDataMap = new()
{
{ HelpSubject.AvatarCaching, "avatar caching" },
{ HelpSubject.Subdomain, "subdomain" },
{ HelpSubject.AvatarConfig, "avatar config" },
{ HelpSubject.GltfDeferAgent, "gltf defer agent" },
{ HelpSubject.LoadingAvatars, "download avatar into scene" },
{
HelpSubject.Avatars, "avatars body type"
}
};
private bool isEnabled;
private readonly AppData appData;
public AmplitudeEditorLogger(bool isEnabled)
{
this.isEnabled = isEnabled;
appData = ApplicationData.GetData();
}
public void Enable()
{
isEnabled = true;
if (!AmplitudeEventLogger.IsSessionIdSet())
{
GenerateSessionId();
}
ToggleAnalytics(true);
}
public void Disable()
{
ToggleAnalytics(false);
isEnabled = false;
AmplitudeEventLogger.SetSessionId(0);
}
public void IdentifyUser()
{
if (!isEnabled) return;
if (!AmplitudeEventLogger.IsSessionIdSet())
{
GenerateSessionId();
}
SetUserProperties();
}
public void LogOpenProject()
{
if (!isEnabled) return;
GenerateSessionId();
AmplitudeEventLogger.LogEvent(EventName.OPEN_PROJECT);
}
public void LogCloseProject()
{
LogEvent(EventName.CLOSE_PROJECT);
}
public void LogOpenDocumentation(string target)
{
LogEvent(EventName.OPEN_DOCUMENTATION, new Dictionary<string, object>
{
{ Properties.TARGET, target }
});
}
public void LogOpenFaq(string target)
{
LogEvent(EventName.OPEN_FAQ, new Dictionary<string, object>
{
{ Properties.TARGET, target }
});
}
public void LogOpenDiscord(string target)
{
LogEvent(EventName.OPEN_DISCORD, new Dictionary<string, object>
{
{ Properties.TARGET, target }
});
}
public void LogLoadAvatarFromDialog(string avatarUrl, bool eyeAnimation, bool voiceHandler)
{
LogEvent(EventName.LOAD_AVATAR_FROM_DIALOG, new Dictionary<string, object>
{
{ Properties.AVATAR_URL, avatarUrl },
{ Properties.EYE_ANIMATION, eyeAnimation },
{ Properties.VOICE_HANDLER, voiceHandler }
});
}
public void LogUpdatePartnerURL(string previousSubdomain, string newSubdomain)
{
LogEvent(EventName.UPDATED_PARTNER_URL, new Dictionary<string, object>
{
{ Properties.PREVIOUS_SUBDOMAIN, previousSubdomain },
{ Properties.NEW_SUBDOMAIN, newSubdomain }
}, new Dictionary<string, object>
{
{ Properties.SUBDOMAIN, newSubdomain }
});
}
public void LogOpenDialog(string dialog)
{
LogEvent(EventName.OPEN_DIALOG, new Dictionary<string, object>
{
{ Properties.DIALOG, dialog }
});
}
public void LogBuildApplication(string target, string appName, bool productionBuild)
{
LogEvent(EventName.BUILD_APPLICATION, new Dictionary<string, object>
{
{ Properties.TARGET, target },
{ Properties.APP_NAME, appName },
{ Properties.PRODUCTION_BUILD, productionBuild },
{ Properties.APP_IDENTIFIER, Application.identifier }
});
}
public void LogMetadataDownloaded(double duration)
{
LogEvent(EventName.METADATA_DOWNLOADED, new Dictionary<string, object>
{
{ Properties.DURATION, duration }
});
}
public void LogAvatarLoaded(double duration)
{
LogEvent(EventName.AVATAR_LOADED, new Dictionary<string, object>
{
{ Properties.DURATION, duration }
});
}
public void LogCheckForUpdates()
{
LogEvent(EventName.CHECK_FOR_UPDATES);
}
public void LogSetLoggingEnabled(bool isLoggingEnabled)
{
LogEvent(EventName.SET_LOGGING_ENABLED, new Dictionary<string, object>
{
{ Properties.LOGGING_ENABLED, isLoggingEnabled }
});
}
public void LogSetCachingEnabled(bool isCachingEnabled)
{
LogEvent(EventName.SET_CACHING_ENABLED, new Dictionary<string, object>
{
{ Properties.CACHING_ENABLED, isCachingEnabled }
});
}
public void LogClearLocalCache()
{
LogEvent(EventName.CLEAR_LOCAL_CACHE);
}
public void LogViewPrivacyPolicy()
{
LogEvent(EventName.PRIVACY_POLICY);
}
public void LogShowInExplorer()
{
LogEvent(EventName.SHOW_IN_EXPLORER);
}
public void LogFindOutMore(HelpSubject subject)
{
LogEvent(EventName.FIND_OUT_MORE, new Dictionary<string, object>
{
{ Properties.CONTEXT, helpDataMap[subject] }
});
}
public void LogOpenSetupGuide()
{
LogEvent(EventName.OPEN_SETUP_GUIDE);
}
public void LogOpenIntegrationGuide()
{
LogEvent(EventName.OPEN_INTEGRATION_GUIDE);
}
public void LogLoadQuickStartScene()
{
LogEvent(EventName.LOAD_QUICK_START_SCENE);
}
public void LogOpenAvatarDocumentation()
{
LogEvent(EventName.OPEN_AVATAR_DOCUMENTATION);
}
public void LogOpenAnimationDocumentation()
{
LogEvent(EventName.OPEN_ANIMATION_DOCUMENTATION);
}
public void LogOpenAvatarCreatorDocumentation()
{
LogEvent(EventName.OPEN_AVATAR_CREATOR_DOCUMENTATION);
}
public void LogOpenOptimizationDocumentation()
{
LogEvent(EventName.OPEN_OPTIMIZATION_DOCUMENTATION);
}
public void LogAvatarCreatorSampleImported()
{
LogEvent(EventName.AVATAR_CREATOR_SAMPLE_IMPORTED);
}
public void LogPackageInstalled(string id, string name)
{
LogEvent(EventName.INSTALL_PACKAGE, new Dictionary<string, object>
{
{ "id", id },
{ "name", name }
});
}
private void SetUserProperties()
{
var userProperties = new Dictionary<string, object>
{
{ Properties.SDK_SOURCE_URL, PackageManagerHelper.GetSdkPackageSourceUrl() },
{ Properties.ENGINE_VERSION, appData.UnityVersion },
{ Properties.RENDER_PIPELINE, appData.RenderPipeline },
{ Properties.SUBDOMAIN, appData.PartnerName },
{ Properties.APP_NAME, PlayerSettings.productName },
{ Properties.SDK_TARGET, SDK_TARGET },
{ Properties.APP_IDENTIFIER, Application.identifier },
{ Properties.ALLOW_ANALYTICS, true }
};
var modules = ModuleList.GetInstalledModuleVersionDictionary();
foreach (var module in modules)
{
userProperties.Add(module.Key, module.Value);
}
LogEvent(EventName.SET_USER_PROPERTIES, null, userProperties);
}
private void GenerateSessionId()
{
AmplitudeEventLogger.SetSessionId(DateTimeOffset.Now.ToUnixTimeMilliseconds());
}
private void ToggleAnalytics(bool allow)
{
LogEvent(EventName.ALLOW_ANALYTICS, new Dictionary<string, object>
{
{ Properties.ALLOW, allow }
}, new Dictionary<string, object>
{
{ Properties.ENGINE_VERSION, appData.UnityVersion },
{ Properties.RENDER_PIPELINE, appData.RenderPipeline },
{ Properties.SUBDOMAIN, appData.PartnerName },
{ Properties.APP_NAME, PlayerSettings.productName },
{ Properties.SDK_TARGET, "Unity" },
{ Properties.APP_IDENTIFIER, Application.identifier },
{ Properties.ALLOW_ANALYTICS, allow }
});
}
private void LogEvent(string eventName, Dictionary<string, object> eventProperties = null, Dictionary<string, object> userProperties = null)
{
if (!isEnabled) return;
AmplitudeEventLogger.LogEvent(eventName, eventProperties, userProperties);
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: ed6804cd2c9d4b9bb873a4c1cd6af062
timeCreated: 1657032252
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Analytics/AmplitudeEditorLogger.cs
uploadId: 704624
@@ -0,0 +1,31 @@
using ReadyPlayerMe.Core.Editor;
namespace ReadyPlayerMe.Core.Analytics
{
public static class AnalyticsEditorLogger
{
public static readonly IAnalyticsEditorLogger EventLogger;
static AnalyticsEditorLogger()
{
IsEnabled = CoreSettingsHandler.CoreSettings.EnableAnalytics;
EventLogger = new AmplitudeEditorLogger(IsEnabled);
}
public static bool IsEnabled { get; private set; }
public static void Enable()
{
IsEnabled = true;
EventLogger.Enable();
CoreSettingsSetter.SetEnableAnalytics(true);
}
public static void Disable()
{
EventLogger.Disable();
IsEnabled = false;
CoreSettingsSetter.SetEnableAnalytics(false);
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: fc2862cbf129461eaa91ca136d9d045d
timeCreated: 1658921992
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Analytics/AnalyticsEditorLogger.cs
uploadId: 704624
@@ -0,0 +1,74 @@
namespace ReadyPlayerMe.Core.Analytics
{
public static class Constants
{
public static class EventName
{
public const string OPEN_PROJECT = "open project";
public const string OPEN_DOCUMENTATION = "open documentation";
public const string OPEN_FAQ = "open faq";
public const string OPEN_DISCORD = "open discord";
public const string LOAD_AVATAR_FROM_DIALOG = "load avatar from dialog";
public const string UPDATED_PARTNER_URL = "updated partner url";
public const string ALLOW_ANALYTICS = "allow analytics";
public const string OPEN_DIALOG = "open dialog";
public const string BUILD_APPLICATION = "build application";
public const string CLOSE_PROJECT = "close project";
public const string METADATA_DOWNLOADED = "metadata downloaded";
public const string AVATAR_LOADED = "avatar loaded";
public const string SET_USER_PROPERTIES = "set user properties";
public const string CLEAR_LOCAL_CACHE = "clear local cache";
public const string SHOW_IN_EXPLORER = "show in explorer";
public const string SET_LOGGING_ENABLED = "set logging enabled";
public const string SET_CACHING_ENABLED = "set caching enabled";
public const string CHECK_FOR_UPDATES = "check for updates";
public const string PRIVACY_POLICY = "view privacy policy";
public const string FIND_OUT_MORE = "find out more";
public const string OPEN_SETUP_GUIDE = "open setup guide";
public const string OPEN_INTEGRATION_GUIDE = "open integration guide";
public const string LOAD_QUICK_START_SCENE = "load quick start scene";
public const string OPEN_AVATAR_DOCUMENTATION = "open avatar documentation";
public const string OPEN_ANIMATION_DOCUMENTATION = "open animation documentation";
public const string OPEN_AVATAR_CREATOR_DOCUMENTATION = "open avatar creator documentation";
public const string OPEN_OPTIMIZATION_DOCUMENTATION = "open optimization documentation";
public const string AVATAR_CREATOR_SAMPLE_IMPORTED = "Avatar creator sample imported";
public const string INSTALL_PACKAGE = "install unity package";
}
public static class Properties
{
public const string SDK_SOURCE_URL = "sdk source url";
public const string ENGINE_VERSION = "engine version";
public const string RENDER_PIPELINE = "render pipeline";
public const string SUBDOMAIN = "subdomain";
public const string APP_NAME = "app name";
public const string SDK_TARGET = "sdk target";
public const string TARGET = "target";
public const string EYE_ANIMATION = "eye animation";
public const string VOICE_HANDLER = "voice handler";
public const string PREVIOUS_SUBDOMAIN = "previous subdomain";
public const string NEW_SUBDOMAIN = "new subdomain";
public const string ALLOW = "allow";
public const string DIALOG = "dialog";
public const string PRODUCTION_BUILD = "production build";
public const string AVATAR_URL = "avatar url";
public const string APP_IDENTIFIER = "app identifier";
public const string ALLOW_ANALYTICS = "allow analytics";
public const string DURATION = "duration";
public const string LOGGING_ENABLED = "logging enabled";
public const string CACHING_ENABLED = "caching enabled";
public const string CONTEXT = "context";
}
public static class Links
{
public const string DOCS_PARTNERS_LINK = "https://docs.readyplayer.me/ready-player-me/what-is-ready-player-me#url";
public const string DOCS_DEFER_AGENT_LINK = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/optimize/defer-agents";
public const string DOCS_AVATAR_LOADER_WINDOW = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/avatar-loader-window";
public const string DOCS_AVATAR_CONFIG_LINK = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/optimize/avatar-configuration";
public const string DOCS_AVATAR_CACHING = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/optimize/avatar-caching";
public const string AVATARS = "https://docs.readyplayer.me/ready-player-me/api-reference/avatars";
public const string APP_ID = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/avatar-creator/custom-avatar-creator#prerequisites";
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: e7e6b1c7b30a462e971d46dd09b38bdf
timeCreated: 1657013679
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Analytics/Constants.cs
uploadId: 704624
@@ -0,0 +1,12 @@
namespace ReadyPlayerMe.Core.Analytics
{
public enum HelpSubject
{
AvatarCaching,
Subdomain,
AvatarConfig,
GltfDeferAgent,
LoadingAvatars,
Avatars
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 38767189f66d5bc4d8dfe76b552103f5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Analytics/HelpSubject.cs
uploadId: 704624
@@ -0,0 +1,36 @@
namespace ReadyPlayerMe.Core.Analytics
{
public interface IAnalyticsEditorLogger
{
void Enable();
void Disable();
void IdentifyUser();
void LogOpenProject();
void LogCloseProject();
void LogOpenDocumentation(string target);
void LogOpenFaq(string target);
void LogOpenDiscord(string target);
void LogLoadAvatarFromDialog(string avatarUrl, bool eyeAnimation, bool voiceHandler);
void LogUpdatePartnerURL(string previousSubdomain, string newSubdomain);
void LogOpenDialog(string dialog);
void LogBuildApplication(string target, string appName, bool productionBuild);
void LogMetadataDownloaded(double duration);
void LogAvatarLoaded(double duration);
void LogCheckForUpdates();
void LogSetLoggingEnabled(bool isLoggingEnabled);
void LogSetCachingEnabled(bool isCachingEnabled);
void LogClearLocalCache();
void LogViewPrivacyPolicy();
void LogShowInExplorer();
void LogFindOutMore(HelpSubject subject);
void LogOpenSetupGuide();
void LogOpenIntegrationGuide();
void LogLoadQuickStartScene();
void LogOpenAvatarDocumentation();
void LogOpenAnimationDocumentation();
void LogOpenAvatarCreatorDocumentation();
void LogOpenOptimizationDocumentation();
void LogAvatarCreatorSampleImported();
void LogPackageInstalled(string id, string name);
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 2a73e3153ee348d199f878b693a5e1f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Analytics/IAnalyticsEditorLogger.cs
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 56a89e876009bc043b3211c63f594371
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,16 @@
using System;
using System.Text.RegularExpressions;
namespace ReadyPlayerMe.Core.Editor
{
public static class StringExtensions
{
private const string SHORT_CODE_REGEX = "^[A-Z0-9]{6}$";
public static bool IsUrlShortcodeValid(this string urlString)
{
return !string.IsNullOrEmpty(urlString) &&
(Regex.Match(urlString, SHORT_CODE_REGEX).Length > 0 || Uri.IsWellFormedUriString(urlString, UriKind.Absolute) && urlString.EndsWith(".glb"));
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: d58d3d8f33d435f4aa8b5b0b6625bcbb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Extensions/StringExtensions.cs
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c882a7949df662b428444bc798c7ebb8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,48 @@
using System;
using ReadyPlayerMe.Core.Analytics;
using UnityEditor;
namespace ReadyPlayerMe.Core.Editor
{
/// <summary>
/// This class serves as a way of tracking when the Unity project (editor) is initially opened so that functions can be run at this point.
/// </summary>
[InitializeOnLoad]
public static class EntryPoint
{
private const string SESSION_STARTED_KEY = "SessionStarted";
/// Event for when package is imported or when project with package is opened.
public static Action Startup;
/// <summary>
/// This constructor is used to subscribe to the <see cref="EditorApplication.update"/> event.
/// </summary>
static EntryPoint()
{
if (!SessionState.GetBool(SESSION_STARTED_KEY, false))
{
SessionState.SetBool(SESSION_STARTED_KEY, true);
EditorApplication.update += Update;
}
}
/// <summary>
/// This function is called on every Editor <see cref="EditorApplication.update"/>.
/// It is used to trigger moduleUpdater to check for updates when the Unity Project launches.
/// </summary>
private static void Update()
{
EditorApplication.update -= Update;
AnalyticsEditorLogger.EventLogger.LogOpenProject();
AnalyticsEditorLogger.EventLogger.IdentifyUser();
Startup?.Invoke();
EditorApplication.quitting += OnQuit;
}
private static void OnQuit()
{
AnalyticsEditorLogger.EventLogger.LogCloseProject();
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 71bde74e39624415805f1552261fd75e
timeCreated: 1657016805
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/ModuleManagement/EntryPoint.cs
uploadId: 704624
@@ -0,0 +1,37 @@
using System;
namespace ReadyPlayerMe.Core.Editor
{
/// <summary>
/// Structure <c>ModuleInfo</c> describes a Ready Player Me Module or Unity package.
/// </summary>
[Serializable]
public struct ModuleInfo
{
public string name;
public string gitUrl;
public string branch;
public string version;
/// <summary>
/// Get the Unity package identifier.
/// </summary>
/// <returns>
/// A <c>string</c> representing the Unity packages Git Url including branch if specified. Returns module name if
/// gitUrl is not set.
/// </returns>
public string Identifier
{
get
{
if (gitUrl == string.Empty)
{
return name;
}
// if branch not set, default to the version in ModuleList
return gitUrl + (string.IsNullOrEmpty(branch) ? $"#v{version}" : $"#{branch}");
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: f14ac780c523d32408d7ea9c6f78e692
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/ModuleManagement/ModuleInfo.cs
uploadId: 704624
@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using UnityEditor;
using UnityEditor.Compilation;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
namespace ReadyPlayerMe.Core.Editor
{
/// <summary>
/// Class <c>ModuleInstaller</c> is responsible for checking and installing all modules (Unity packages) required for
/// the Ready Player Me Unity SDK from their Git URL's.
/// </summary>
[InitializeOnLoad]
public static class ModuleInstaller
{
private const string TAG = nameof(ModuleInstaller);
private const int THREAD_SLEEP_TIME = 100;
private const float TIMEOUT_FOR_MODULE_INSTALLATION = 20f;
static ModuleInstaller()
{
Events.registeringPackages -= OnRegisteringPackages;
Events.registeringPackages += OnRegisteringPackages;
#if !READY_PLAYER_ME
EditorApplication.delayCall += DelayCreateCoreSettings;
DefineSymbolHelper.AddSymbols();
#endif
}
/// <summary>
/// Called when a package is about to be added, removed or changed.
/// </summary>
/// <param name="args">Describes the <c>PackageInfo</c> entries of packages currently registering.</param>
private static void OnRegisteringPackages(PackageRegistrationEventArgs args)
{
// Core module uninstalled
if (args.removed != null && args.removed.Any(p => p.name == ModuleList.Core.name))
{
DefineSymbolHelper.RemoveSymbols();
ProjectPrefs.SetBool(ProjectPrefs.FIRST_TIME_SETUP_DONE, false);
}
}
private static void DelayCreateCoreSettings()
{
EditorApplication.delayCall -= DelayCreateCoreSettings;
CoreSettingsLoader.EnsureSettingsExist();
}
/// <summary>
/// Request UPM to install the given module with the identifier.
/// </summary>
/// <param name="identifier">The Unity package identifier of the module to be installed.</param>
public static void AddModuleRequest(string identifier)
{
var startTime = Time.realtimeSinceStartup;
AddRequest addRequest = Client.Add(identifier);
while (!addRequest.IsCompleted && Time.realtimeSinceStartup - startTime < TIMEOUT_FOR_MODULE_INSTALLATION)
Thread.Sleep(THREAD_SLEEP_TIME);
if (Time.realtimeSinceStartup - startTime >= TIMEOUT_FOR_MODULE_INSTALLATION)
{
Debug.LogError($"Package installation timed out for {identifier}. Please try again.");
}
if (addRequest.Error != null)
{
Debug.LogError("Error: " + addRequest.Error.message);
}
}
/// <summary>
/// Check if the given module with the name is currently installed.
/// </summary>
/// <param name="name">Name of the module.</param>
/// <returns>A boolean <c>true</c> if the module is installed.</returns>
public static bool IsModuleInstalled(string name)
{
return GetPackageList().Any(info => info.name == name);
}
/// <summary>
/// Get the list of unity packages installed in the current project.
/// </summary>
/// <returns>An array of <c>PackageInfo</c>.</returns>
public static PackageInfo[] GetPackageList()
{
ListRequest listRequest = Client.List(true);
while (!listRequest.IsCompleted)
Thread.Sleep(THREAD_SLEEP_TIME);
if (listRequest.Error != null)
{
SDKLogger.Log(TAG, "Error: " + listRequest.Error.message);
return Array.Empty<PackageInfo>();
}
return listRequest.Result.ToArray();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 5201abe9c7e36574d90cd052f0e8cda3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/ModuleManagement/ModuleInstaller.cs
uploadId: 704624
@@ -0,0 +1,72 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor.PackageManager;
namespace ReadyPlayerMe.Core.Editor
{
/// <summary>
/// Class <c>ModuleList</c> is a static class that can be referenced to get the latest module version.
/// </summary>
public static class ModuleList
{
public static ModuleInfo Core = new ModuleInfo
{
name = "com.readyplayerme.core",
gitUrl = "https://github.com/readyplayerme/rpm-unity-sdk-core.git",
branch = "",
version = "5.0.0"
};
/// <summary>
/// A static list of all the required modules represented in an array of <c>ModuleInfo</c>.
/// </summary>
public static readonly ModuleInfo[] Modules =
{
new ModuleInfo
{
name = "com.readyplayerme.webview",
gitUrl = "https://github.com/readyplayerme/rpm-unity-sdk-webview.git",
branch = "",
version = "2.1.3"
}
};
/// <summary>
/// Unity Module that adds support for gltf files that use DracoCompression.
/// </summary>
public static ModuleInfo DracoCompression = new ModuleInfo
{
name = "com.atteneder.draco",
gitUrl = "https://github.com/atteneder/DracoUnity.git",
branch = "",
version = "4.1.0"
};
/// <summary>
/// Get installed modules from Modules list.
/// </summary>
/// <returns>A <see cref="Dictionary"/> of installed Unity Module information in the format of <c>Dictionary&lt;string: name, string: version&gt;</c>. </returns>
public static Dictionary<string, string> GetInstalledModuleVersionDictionary()
{
PackageInfo[] packageList = ModuleInstaller.GetPackageList();
var installedModules = new Dictionary<string, string>();
installedModules.Add(Core.name, Core.version);
foreach (ModuleInfo module in Modules)
{
if (packageList.Any(x => x.name == module.name))
{
installedModules.Add(module.name, module.version);
}
}
if (packageList.Any(x => x.name == DracoCompression.name))
{
installedModules.Add(DracoCompression.name, DracoCompression.version);
}
return installedModules;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 725bcc26dc146374c8f0d96d3928d7ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/ModuleManagement/ModuleList.cs
uploadId: 704624
@@ -0,0 +1,211 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using ReadyPlayerMe.Core.Analytics;
using UnityEditor;
using UnityEditor.PackageManager;
using UnityEditor.PackageManager.Requests;
using UnityEngine;
using UnityEngine.Networking;
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
namespace ReadyPlayerMe.Core.Editor
{
/// <summary>
/// It is responsible for checking and updating the Ready Player Me SDK modules.
/// </summary>
[InitializeOnLoad]
public class ModuleUpdater
{
private class Release
{
[JsonProperty("tag_name")]
public string Tag;
}
private const string PACKAGE_JSON = "package.json";
private const string PACKAGE_DOMAIN = "com.readyplayerme";
private const string GITHUB_WEBSITE = "https://github.com";
private const string GITHUB_API_URL = "https://api.github.com/repos";
private const int MILLISECONDS_TIMEOUT = 20;
private const string ASSET_FILTER = "package";
private const string DONT_ASK = "Dont Ask";
private const string UPDATE_PACKAGES_WINDOW_TITLE = "Update Packages";
private const string UPDATE_BUTTON_TEXT = "Update";
private const string CANCEL_BUTTON_TEXT = "Cancel";
private const string DONT_ASK_TEXT = "Don't ask";
private const string AVATAR_LOADER_PACKAGE = "com.readyplayerme.avatarloader";
static ModuleUpdater()
{
EntryPoint.Startup += () => Check(true);
}
/// <summary>
/// Check for Ready Player Me package updates.
/// </summary>
[MenuItem("Tools/Ready Player Me/Check For Updates", priority = 23)]
public static void CheckForUpdates()
{
AnalyticsEditorLogger.EventLogger.LogCheckForUpdates();
Check();
}
private static void Check(bool isStartup = false)
{
// Get PackageInfo array from RPM Module package.json files
PackageInfo[] packages = AssetDatabase.FindAssets(ASSET_FILTER)
.Select(AssetDatabase.GUIDToAssetPath)
.Where(x => x.Contains(PACKAGE_JSON) && x.Contains(PACKAGE_DOMAIN))
.Select(PackageInfo.FindForAssetPath)
.ToArray();
if (packages.Length == 0)
{
Debug.Log("No rpm package found");
}
// Turn package_name@repo_url#branch_name into https://api.github.com/repos/readyplayerme/repo_name/releases
foreach (PackageInfo package in packages)
{
var repoUrl = package.packageId.Split('@')[1];
var releasesUrl = repoUrl
.Split(new[] { ".git" }, StringSplitOptions.None)[0]
.Replace(GITHUB_WEBSITE, GITHUB_API_URL) + "/releases";
var packageUrl = repoUrl.Split('#')[0];
// Experimental or prerelease packages might look like 0.1.0-exp.1, remove after dash to parse with Version
var version = package.version.Split('-')[0];
if (isStartup && EditorPrefs.GetBool(DONT_ASK + "-" + package.name))
{
continue;
}
FetchReleases(package.name, packageUrl, releasesUrl, new Version(version));
}
}
/// <summary>
/// Fetch latest release for each module and prompt for update if available.
/// </summary>
/// <param name="packageName">The name of the Unity package.</param>
/// <param name="packageUrl">The Git URL of the Unity package.</param>
/// <param name="releasesUrl">The Git URL of the Unity package.</param>
/// <param name="currentVersion">The current version of the package.</param>
private static async void FetchReleases(string packageName, string packageUrl, string releasesUrl,
Version currentVersion)
{
UnityWebRequest request = UnityWebRequest.Get(releasesUrl);
UnityWebRequestAsyncOperation op = request.SendWebRequest();
while (!op.isDone) await Task.Yield();
if (request.result == UnityWebRequest.Result.Success)
{
var response = request.downloadHandler.text;
Release[] releases = JsonConvert.DeserializeObject<Release[]>(response);
Version[] versions = releases!.Select(r => new Version(r.Tag.Substring(1).Split('-')[0])).ToArray();
Version latestVersion = versions.Max();
if (latestVersion > currentVersion)
{
DisplayUpdateDialog(packageName, currentVersion, latestVersion, packageUrl);
}
}
else
{
Debug.Log($"Failed to fetch {packageName} releases. Error: {request.error} ");
}
}
/// <summary>
/// Display a Unity popup with notification about available package updates with buttons to update or skip.
/// </summary>
/// <param name="packageName">The name of the Unity package.</param>
/// <param name="currentVersion">The current version of the package.</param>
/// <param name="latestVersion">The new version of the package.</param>
/// <param name="packageUrl">The Git URL of the Unity package.</param>
private static void DisplayUpdateDialog(string packageName, Version currentVersion, Version latestVersion,
string packageUrl)
{
var shouldUpdate = EditorUtility.DisplayDialogComplex(UPDATE_PACKAGES_WINDOW_TITLE,
$"New update available for {packageName}\nCurrent version: {currentVersion}\nLatest version: {latestVersion}",
UPDATE_BUTTON_TEXT,
CANCEL_BUTTON_TEXT,
DONT_ASK_TEXT);
switch (shouldUpdate)
{
// Update
case 0:
CheckIfMajorRelease(packageName, currentVersion, latestVersion, packageUrl);
break;
// Cancel
case 1:
// Do nothing
break;
// Don't ask
case 2:
EditorPrefs.SetBool(DONT_ASK + "-" + packageName, true);
break;
}
}
private static void CheckIfMajorRelease(string packageName, Version currentVersion, Version latestVersion,
string packageUrl)
{
if (latestVersion.Major > currentVersion.Major)
{
BreakingChangeDialog.ShowDialog(() =>
{
UpdateModule(packageName, packageUrl, currentVersion, latestVersion);
});
}
else
{
UpdateModule(packageName, packageUrl, currentVersion, latestVersion);
}
}
/// <summary>
/// Update the specified module by removing the current version and then adding the specified version.
/// </summary>
/// <param name="name">The name of the Unity package.</param>
/// <param name="url">The Git URL of the Unity package.</param>
/// <param name="current">The current version of the package.</param>
/// <param name="latest">The new version of the package.</param>
private static void UpdateModule(string name, string url, Version current, Version latest)
{
url += "#v" + latest;
CleanRedundantAvatarLoader();
RemoveRequest removeRequest = Client.Remove(name);
while (!removeRequest.IsCompleted) Thread.Sleep(MILLISECONDS_TIMEOUT);
AddRequest addRequest = Client.Add(url);
while (!addRequest.IsCompleted) Thread.Sleep(MILLISECONDS_TIMEOUT);
Debug.Log($"Updated {name} from v{current} to v{latest}");
}
private static void CleanRedundantAvatarLoader()
{
if (!ModuleInstaller.IsModuleInstalled(AVATAR_LOADER_PACKAGE))
{
return;
}
RemoveRequest removeRequest = Client.Remove(AVATAR_LOADER_PACKAGE);
while (!removeRequest.IsCompleted) Thread.Sleep(MILLISECONDS_TIMEOUT);
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 40c5062ebf8390443a66ccca5f9d4507
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/ModuleManagement/ModuleUpdater.cs
uploadId: 704624
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2ac2b39cc7ef4a5988d6ac77077db307
timeCreated: 1699344120
@@ -0,0 +1,35 @@
using System;
using System.Linq;
using ReadyPlayerMe.Core.Analytics;
using UnityEditor;
using UnityEditor.PackageManager;
namespace ReadyPlayerMe.Core.Editor
{
public abstract class PackageManagerEventListener
{
public static event Action<string> OnPackageImported;
[InitializeOnLoadMethod]
static void Initialize()
{
Events.registeredPackages += OnPackagesInstalled;
}
~PackageManagerEventListener()
{
Events.registeredPackages -= OnPackagesInstalled;
}
static void OnPackagesInstalled(PackageRegistrationEventArgs packageRegistrationEventArgs)
{
packageRegistrationEventArgs.added
.ToList()
.ForEach(packageInfo =>
{
OnPackageImported?.Invoke(packageInfo.name);
AnalyticsEditorLogger.EventLogger.LogPackageInstalled(packageInfo.name, packageInfo.packageId);
});
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: a08c3f9ac3c142dc9ea5d854a1bc3af1
timeCreated: 1699344135
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/PackageManager/PackageManagerEventListener.cs
uploadId: 704624
@@ -0,0 +1,68 @@
using System;
using System.Linq;
using System.Threading;
using UnityEditor.PackageManager;
using UnityEngine;
namespace ReadyPlayerMe.Core.Editor
{
public abstract class PackageManagerHelper
{
private const string TAG = nameof(PackageManagerHelper);
private const int THREAD_SLEEP_TIME = 100;
private const float TIMEOUT_FOR_PACKAGE_INSTALLATION = 20f;
private const string READY_PLAYER_ME_PACKAGE_PATH = "Packages/com.readyplayerme.core";
public static bool IsPackageInstalled(string name)
{
return GetPackageList().Any(info => info.name == name);
}
/// <summary>
/// Get the list of unity packages installed in the current project.
/// </summary>
/// <returns>An array of <c>PackageInfo</c>.</returns>
public static PackageInfo[] GetPackageList()
{
var listRequest = Client.List(true);
while (!listRequest.IsCompleted)
Thread.Sleep(THREAD_SLEEP_TIME);
if (listRequest.Error == null)
{
return listRequest.Result.ToArray();
}
SDKLogger.Log(TAG, "Error: " + listRequest.Error.message);
return Array.Empty<PackageInfo>();
}
public static string GetSdkPackageSourceUrl()
{
var sdkPackageInfo = PackageInfo.FindForAssetPath(READY_PLAYER_ME_PACKAGE_PATH);
return sdkPackageInfo?.packageId
.Split(new[] { '@' }, StringSplitOptions.RemoveEmptyEntries)
.LastOrDefault();
}
public static void AddPackage(string identifier)
{
var startTime = Time.realtimeSinceStartup;
var addRequest = Client.Add(identifier);
while (!addRequest.IsCompleted && Time.realtimeSinceStartup - startTime < TIMEOUT_FOR_PACKAGE_INSTALLATION)
Thread.Sleep(THREAD_SLEEP_TIME);
if (Time.realtimeSinceStartup - startTime >= TIMEOUT_FOR_PACKAGE_INSTALLATION)
{
Debug.LogError($"Package installation timed out for {identifier}. Please try again.");
}
if (addRequest.Error != null)
{
Debug.LogError("Error: " + addRequest.Error.message);
}
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 1c12b21e35214e19a1c3dfe7148a3fda
timeCreated: 1698851420
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/PackageManager/PackageManagerHelper.cs
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: dc95a31f3c977d74d95cba569605dbf1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,19 @@
using ReadyPlayerMe.Core.Analytics;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
namespace ReadyPlayerMe.Core.Editor
{
public static class BuildPostProcessor
{
[PostProcessBuild(1)]
public static void OnPostprocessBuild(BuildTarget target, string pathToBuiltProject)
{
// create asset if it has been deleted
CoreSettingsLoader.EnsureSettingsExist();
AppData appData = ApplicationData.GetData();
AnalyticsEditorLogger.EventLogger.LogBuildApplication(appData.BuildTarget, PlayerSettings.productName, !Debug.isDebugBuild);
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 9efa9adc0c4948579b226dac039a2e85
timeCreated: 1657013212
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Processors/BuildPostProcessor.cs
uploadId: 704624
@@ -0,0 +1,40 @@
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;
namespace ReadyPlayerMe.Core.Editor
{
public class BuildPreprocessor : IPreprocessBuildWithReport
{
private const string TAG = nameof(BuildPreprocessor);
private const string ADD_SHADER_VARIANTS = "Add and Build";
private const string BUILD_WARNING = "Build Warning";
private const string SUBDOMAIN_WARNING =
@"It looks like the glTFast Shader Variants are missing from the Graphics Settings/Preloaded Shader list list. This can cause errors when loading Ready Player Me avatars at runtime. Would you like to add them now before building?";
private const string CONTINUE_WITH_DEMO = "Build without Variants";
private const string WARNING_BUILD_WITHOUT_VARIANTS = "Building without adding glTFast Shader Variants";
public int callbackOrder { get; }
public void OnPreprocessBuild(BuildReport report)
{
if (!Application.isBatchMode && GraphicsSettingsUtility.IsMissingVariants())
{
var addShaderVariants = EditorUtility.DisplayDialog(BUILD_WARNING,
SUBDOMAIN_WARNING,
ADD_SHADER_VARIANTS,
CONTINUE_WITH_DEMO);
if (addShaderVariants)
{
GraphicsSettingsUtility.AddPreloadShaderVariants();
}
else
{
SDKLogger.LogWarning(TAG, WARNING_BUILD_WITHOUT_VARIANTS);
}
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 0d1731ba78624114ba8112a23e3033a7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Processors/BuildPreprocessor.cs
uploadId: 704624
@@ -0,0 +1,30 @@
using UnityEditor;
namespace ReadyPlayerMe.Core.Editor
{
public class ModelAssetProcessor : AssetPostprocessor
{
private const string ANIMATION_ASSET_PATH = "Assets/Ready Player Me/Animations";
private void OnPreprocessModel()
{
var modelImporter = assetImporter as ModelImporter;
UpdateAnimationFileSettings(modelImporter);
}
private void UpdateAnimationFileSettings(ModelImporter modelImporter)
{
void SetModelImportData()
{
if (modelImporter is null) return;
modelImporter.useFileScale = false;
modelImporter.animationType = ModelImporterAnimationType.Human;
}
if (assetPath.Contains(ANIMATION_ASSET_PATH))
{
SetModelImportData();
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 42dc49b3ab05c424a80c14e9bfae17e6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Processors/ModelAssetProcessor.cs
uploadId: 704624
@@ -0,0 +1,19 @@
{
"name": "ReadyPlayerMe.Core.Editor",
"rootNamespace": "",
"references": [
"ReadyPlayerMe.Core",
"ReadyPlayerMe.AvatarCreator"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}
@@ -0,0 +1,14 @@
fileFormatVersion: 2
guid: 36f486ff968bbf4439cd840e8fca87ea
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/ReadyPlayerMe.Core.Editor.asmdef
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 52273617608987047a79eb2417aab281
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,44 @@
using UnityEditor;
using UnityEngine;
namespace ReadyPlayerMe.Core.Editor
{
[InitializeOnLoad]
public class AvatarLoaderSettingsCreator
{
private const string SETTINGS_SAVE_FOLDER = "Ready Player Me/Resources/Settings";
private const string AVATAR_LOADER_ASSET_NAME = "AvatarLoaderSettings.asset";
static AvatarLoaderSettingsCreator()
{
EditorApplication.delayCall += CreateSettingsAssets;
}
~AvatarLoaderSettingsCreator()
{
EditorApplication.delayCall -= CreateSettingsAssets;
}
private static void CreateSettingsAssets()
{
if (AvatarLoaderSettings.LoadSettings() != null)
{
return;
}
DirectoryUtility.ValidateDirectory($"{Application.dataPath}/{SETTINGS_SAVE_FOLDER}");
AssetDatabase.Refresh();
CreateAvatarLoaderSettings();
}
private static void CreateAvatarLoaderSettings()
{
var newSettings = ScriptableObject.CreateInstance<AvatarLoaderSettings>();
newSettings.AvatarConfig = null;
newSettings.GLTFDeferAgent = null;
newSettings.AvatarCachingEnabled = true;
AssetDatabase.CreateAsset(newSettings, $"Assets/{SETTINGS_SAVE_FOLDER}/{AVATAR_LOADER_ASSET_NAME}");
AssetDatabase.SaveAssets();
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 1ea257c9bde84481a358e3685eef8646
timeCreated: 1670940169
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Settings/AvatarLoaderSettingsCreator.cs
uploadId: 704624
@@ -0,0 +1,36 @@
using System.IO;
using ReadyPlayerMe.Core.Data;
using UnityEditor;
using UnityEngine;
namespace ReadyPlayerMe.Core.Editor
{
[InitializeOnLoad]
public static class CoreSettingsLoader
{
private const string PROJECT_RELATIVE_ASSET_PATH = "Assets/Ready Player Me/Resources/Settings/CoreSettings.asset";
private const string SETTINGS_SAVE_FOLDER = "Ready Player Me/Resources/Settings";
static CoreSettingsLoader()
{
EnsureSettingsExist();
}
public static void EnsureSettingsExist()
{
if (CoreSettingsHandler.CoreSettings == null && !File.Exists($"{Application.dataPath}/Ready Player Me/Resources/Settings/CoreSettings.asset"))
{
CreateSettings();
}
}
private static void CreateSettings()
{
DirectoryUtility.ValidateDirectory($"{Application.dataPath}/{SETTINGS_SAVE_FOLDER}");
var newSettings = ScriptableObject.CreateInstance<CoreSettings>();
AssetDatabase.CreateAsset(newSettings, PROJECT_RELATIVE_ASSET_PATH);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: da717eefac74935459a3f995092c5463
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Settings/CoreSettingsLoader.cs
uploadId: 704624
@@ -0,0 +1,44 @@
using UnityEditor;
namespace ReadyPlayerMe.Core.Editor
{
public static class CoreSettingsSetter
{
public static void SetEnableAnalytics(bool isEnabled)
{
CoreSettingsHandler.CoreSettings.EnableAnalytics = isEnabled;
Save();
}
public static void SetEnableLogging(bool isEnabled)
{
CoreSettingsHandler.CoreSettings.EnableLogging = isEnabled;
Save();
}
public static void SaveSubDomain(string subDomain)
{
if (string.IsNullOrEmpty(subDomain) || CoreSettingsHandler.CoreSettings.Subdomain == subDomain) return;
CoreSettingsHandler.CoreSettings.Subdomain = subDomain;
Save();
}
public static void SaveAppId(string appId)
{
CoreSettingsHandler.CoreSettings.AppId = appId;
Save();
}
public static void SaveBodyType(BodyType bodyType)
{
CoreSettingsHandler.CoreSettings.BodyType = bodyType;
Save();
}
public static void Save()
{
EditorUtility.SetDirty(CoreSettingsHandler.CoreSettings);
AssetDatabase.SaveAssets();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 79be5f9e434a00b46bacd5a47871b69a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Settings/CoreSettingsSetter.cs
uploadId: 704624
@@ -0,0 +1,138 @@
using System.IO;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
namespace ReadyPlayerMe.Core.Editor
{
public enum RenderPipeline { Standard, URP, HDRP }
public static class GraphicsSettingsUtility
{
private const string TAG = nameof(GraphicsSettingsUtility);
private const string PRELOADED_SHADER_PROPERTY = "m_PreloadedShaders";
private const string GRAPHICS_SETTING_PATH = "ProjectSettings/GraphicsSettings.asset";
private const string SHADER_VARIANT_ASSETS_FOLDER = "Assets/Ready Player Me/Core/Runtime/Core/Shaders";
private const string SHADER_VARIANT_PACKAGES_FOLDER = "Packages/com.readyplayerme.core/Runtime/Core/Shaders";
private const string SHADER_VARIANTS_STANDARD = "glTFastShaderVariants";
private const string SHADER_VARIANTS_URP = "glTFastShaderVariantsURP";
private const string SHADER_VARIANTS_HDRP = "glTFastShaderVariantsHDRP";
private const string HDRP_TYPE_NAME = "HDRenderPipelineAsset";
private const string URP_TYPE_NAME = "UniversalRenderPipelineAsset";
private const string SHADER_SESSION_CHECK = "SHADER_SESSION_CHECK";
private const string VARIANTS_FOUND_LOG = "glTFast shader variants found in Graphics Settings->Preloaded Shaders";
private const string SHADER_VARIANTS_EXTENSION = ".shadervariants";
[InitializeOnLoadMethod]
private static void InitializeOnLoad()
{
if (SessionState.GetBool(SHADER_SESSION_CHECK, false)) return;
SessionState.SetBool(SHADER_SESSION_CHECK, true);
EditorApplication.update += CheckAndUpdatePreloadShaders;
}
private static void CheckAndUpdatePreloadShaders()
{
EditorApplication.update -= CheckAndUpdatePreloadShaders;
AddPreloadShaderVariants(true);
}
public static void AddPreloadShaderVariants(bool checkForMissingVariants = false)
{
var graphicsSettings = AssetDatabase.LoadAssetAtPath<GraphicsSettings>(GRAPHICS_SETTING_PATH);
var serializedGraphicsObject = new SerializedObject(graphicsSettings);
SerializedProperty shaderPreloadArray = serializedGraphicsObject.FindProperty(PRELOADED_SHADER_PROPERTY);
AssetDatabase.Refresh();
var newArrayIndex = shaderPreloadArray.arraySize;
var shaderVariants = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(GetTargetShaderPath());
if (shaderVariants == null)
{
Debug.LogWarning($"Shader variants not found at {GetTargetShaderPath()}");
return;
}
if (checkForMissingVariants)
{
var shadersMissing = true;
var serializedVariants = new SerializedObject(shaderVariants);
foreach (SerializedProperty shaderInclude in shaderPreloadArray)
{
if (shaderInclude.objectReferenceValue.name == serializedVariants.targetObject.name)
{
SDKLogger.Log(TAG, VARIANTS_FOUND_LOG);
shadersMissing = false;
break;
}
}
if (!shadersMissing) return;
}
shaderPreloadArray.InsertArrayElementAtIndex(newArrayIndex);
SerializedProperty shaderInArray = shaderPreloadArray.GetArrayElementAtIndex(newArrayIndex);
shaderInArray.objectReferenceValue = shaderVariants;
serializedGraphicsObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
}
public static bool IsMissingVariants()
{
var graphicsSettings = AssetDatabase.LoadAssetAtPath<GraphicsSettings>(GRAPHICS_SETTING_PATH);
var serializedGraphicsObject = new SerializedObject(graphicsSettings);
SerializedProperty shaderPreloadArray = serializedGraphicsObject.FindProperty(PRELOADED_SHADER_PROPERTY);
var shaderVariants = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(GetTargetShaderPath());
var shadersMissing = true;
var serializedVariants = new SerializedObject(shaderVariants);
foreach (SerializedProperty shaderInclude in shaderPreloadArray)
{
if (shaderInclude.objectReferenceValue.name == serializedVariants.targetObject.name)
{
SDKLogger.Log(TAG, VARIANTS_FOUND_LOG);
shadersMissing = false;
break;
}
}
return shadersMissing;
}
private static string GetTargetShaderPath()
{
var shaderFolderPath = SHADER_VARIANT_PACKAGES_FOLDER;
if (!Directory.Exists(shaderFolderPath))
{
shaderFolderPath = SHADER_VARIANT_ASSETS_FOLDER;
}
return GetCurrentRenderPipeline() switch
{
RenderPipeline.URP => $"{shaderFolderPath}/{SHADER_VARIANTS_URP}{SHADER_VARIANTS_EXTENSION}",
RenderPipeline.HDRP => $"{shaderFolderPath}/{SHADER_VARIANTS_HDRP}{SHADER_VARIANTS_EXTENSION}",
_ => $"{shaderFolderPath}/{SHADER_VARIANTS_STANDARD}{SHADER_VARIANTS_EXTENSION}"
};
}
private static RenderPipeline GetCurrentRenderPipeline()
{
if (GraphicsSettings.defaultRenderPipeline != null)
{
var renderPipelineType = GraphicsSettings.defaultRenderPipeline.GetType().ToString();
if (renderPipelineType.Contains(HDRP_TYPE_NAME))
{
return RenderPipeline.HDRP;
}
if (renderPipelineType.Contains(URP_TYPE_NAME))
{
return RenderPipeline.URP;
}
}
return RenderPipeline.Standard;
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 6d2fbb1ef6a68bc4b9c0c99be430c64d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/Settings/GraphicsSettingsUtility.cs
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 18404e155f36da7408078998b6470ce2
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 669755add08ba044d9ffb4e764476d9d
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,430 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace ReadyPlayerMe.Core.Editor
{
[CustomEditor(typeof(AvatarConfig))]
public class AvatarConfigEditor : UnityEditor.Editor
{
private const string DIALOG_TITLE = "Read Player Me";
private const string DIALOG_MESSAGE = "Do you want to install {0} Unity Package: {1} ?";
private const string DIALOG_OK = "Ok";
private const string DIALOG_CANCEL = "Cancel";
private const string ADD_MORPH_TARGET = "Add Morph Target";
private const string DELETE_MORPH_TARGET = "Delete Morph Target";
private const string REMOVE_BUTTON_TEXT = "Remove";
private const string MESH_OPT_PACKAGE_NAME = "com.unity.meshopt.decompress";
[SerializeField] private VisualTreeAsset visualTreeAsset;
private AvatarConfig avatarConfigTarget;
private List<Label> morphTargetLabels;
private Dictionary<VisualElement, string> morphTargetsParentVisualElement;
private VisualElement selectedMorphTargets;
private SerializedProperty useDracoCompressionField;
private bool previousDracoCompressionValue;
private SerializedProperty useMeshOptCompressionField;
private bool previousMeshOptCompressionValue;
private VisualElement root;
private Action textureChannelChanged;
private SerializedProperty shaderPropertyMappingList;
public override VisualElement CreateInspectorGUI()
{
root = new VisualElement();
visualTreeAsset.CloneTree(root);
avatarConfigTarget = (AvatarConfig) target;
shaderPropertyMappingList = serializedObject.FindProperty("ShaderPropertyMapping");
SetupLod();
SetupPose();
SetupTextureAtlas();
SetupTextureSizeLimit();
SetupUseHands();
SetupCompressionPackages();
SetupTextureChannel();
SetupMorphTargets();
SetupShader();
return root;
}
private void SetupLod()
{
var lod = root.Q<EnumField>("Lod");
lod.SetValueWithoutNotify(avatarConfigTarget.Lod);
lod.RegisterValueChangedCallback(x =>
{
avatarConfigTarget.Lod = (Lod) x.newValue;
Save();
}
);
}
private void SetupPose()
{
var pose = root.Q<EnumField>("Pose");
pose.SetValueWithoutNotify(avatarConfigTarget.Pose);
pose.RegisterValueChangedCallback(x =>
{
avatarConfigTarget.Pose = (Pose) x.newValue;
Save();
}
);
}
private void Save()
{
serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(serializedObject.targetObject);
}
private void SetupTextureAtlas()
{
var textureAtlas = root.Q<EnumField>("TextureAtlas");
textureAtlas.SetValueWithoutNotify(avatarConfigTarget.TextureAtlas);
textureAtlas.RegisterValueChangedCallback(x =>
{
avatarConfigTarget.TextureAtlas = (TextureAtlas) x.newValue;
Save();
}
);
}
private void SetupTextureSizeLimit()
{
var textureSizeLimit = root.Q<SliderInt>("TextureSizeLimit");
textureSizeLimit.SetValueWithoutNotify(avatarConfigTarget.TextureSizeLimit);
textureSizeLimit.RegisterValueChangedCallback(x =>
{
avatarConfigTarget.TextureSizeLimit = x.newValue;
Save();
}
);
}
private void SetupUseHands()
{
var useHands = root.Q<Toggle>("UseHands");
useHands.SetValueWithoutNotify(avatarConfigTarget.UseHands);
useHands.RegisterValueChangedCallback(x =>
{
avatarConfigTarget.UseHands = x.newValue;
Save();
}
);
}
private void SetupCompressionPackages()
{
var useDracoCompression = root.Q<Toggle>("UseDracoCompression");
var useMeshOptCompression = root.Q<Toggle>("UseMeshOptCompression");
var optimizationPackages = root.Q<Foldout>("OptimizationPackages");
optimizationPackages.RegisterValueChangedCallback(x =>
{
useDracoCompression.SetValueWithoutNotify(avatarConfigTarget.UseDracoCompression);
useMeshOptCompression.SetValueWithoutNotify(avatarConfigTarget.UseMeshOptCompression);
});
useDracoCompression.RegisterValueChangedCallback(x =>
{
if (avatarConfigTarget.UseDracoCompression == x.newValue) return;
avatarConfigTarget.UseDracoCompression = x.newValue;
if (!ModuleInstaller.IsModuleInstalled(ModuleList.DracoCompression.name))
{
if (EditorUtility.DisplayDialog(
DIALOG_TITLE,
string.Format(DIALOG_MESSAGE, "Draco compression", ModuleList.DracoCompression.name),
DIALOG_OK,
DIALOG_CANCEL))
{
ModuleInstaller.AddModuleRequest(ModuleList.DracoCompression.Identifier);
}
else
{
avatarConfigTarget.UseDracoCompression = false;
}
}
useDracoCompression.SetValueWithoutNotify(avatarConfigTarget.UseDracoCompression);
if (avatarConfigTarget.UseDracoCompression && avatarConfigTarget.UseMeshOptCompression)
{
Debug.LogWarning("Draco compression is not compatible with Mesh Optimization compression. Mesh Optimization compression will be disabled.");
avatarConfigTarget.UseMeshOptCompression = false;
useMeshOptCompression.SetValueWithoutNotify(false);
}
Save();
}
);
useMeshOptCompression.RegisterValueChangedCallback(x =>
{
if (avatarConfigTarget.UseMeshOptCompression == x.newValue) return;
avatarConfigTarget.UseMeshOptCompression = x.newValue;
if (!PackageManagerHelper.IsPackageInstalled(MESH_OPT_PACKAGE_NAME))
{
if (EditorUtility.DisplayDialog(
DIALOG_TITLE,
string.Format(DIALOG_MESSAGE, "Mesh opt compression", MESH_OPT_PACKAGE_NAME),
DIALOG_OK,
DIALOG_CANCEL))
{
PackageManagerHelper.AddPackage(MESH_OPT_PACKAGE_NAME);
}
else
{
avatarConfigTarget.UseMeshOptCompression = false;
}
}
useMeshOptCompression.SetValueWithoutNotify(avatarConfigTarget.UseMeshOptCompression);
if (avatarConfigTarget.UseMeshOptCompression && avatarConfigTarget.UseDracoCompression)
{
Debug.LogWarning("Mesh Optimization compression is not compatible with Draco compression. Draco compression will be disabled.");
avatarConfigTarget.UseDracoCompression = false;
useDracoCompression.SetValueWithoutNotify(false);
}
Save();
}
);
}
private void SetupTextureChannel()
{
var items = new List<string>();
foreach (TextureChannel textureChannel in Enum.GetValues(typeof(TextureChannel)))
{
items.Add(textureChannel.ToString());
}
VisualElement MakeItem()
{
var toggle = new Toggle();
toggle.style.alignItems = Align.Center;
return toggle;
}
void BindItem(VisualElement e, int i)
{
var toggle = (Toggle) e;
toggle.label = items[i];
if (avatarConfigTarget.TextureChannel.Contains((TextureChannel) i))
{
toggle.SetValueWithoutNotify(true);
}
toggle.RegisterValueChangedCallback(x =>
{
if (x.newValue)
{
var textureChannels = avatarConfigTarget.TextureChannel.ToList();
textureChannels.Add((TextureChannel) i);
avatarConfigTarget.TextureChannel = textureChannels.ToArray();
textureChannelChanged?.Invoke();
}
else
{
var textureChannels = avatarConfigTarget.TextureChannel.ToList();
textureChannels.Remove((TextureChannel) i);
avatarConfigTarget.TextureChannel = textureChannels.ToArray();
textureChannelChanged?.Invoke();
}
Save();
});
}
var listView = root.Q<ListView>();
listView.style.height = 30 * Enum.GetValues(typeof(TextureChannel)).Length + 2;
listView.makeItem = MakeItem;
listView.bindItem = BindItem;
listView.itemsSource = items;
listView.selectionType = SelectionType.Multiple;
listView.onItemsChosen += Debug.Log;
listView.onSelectionChange += Debug.Log;
}
private void SetupShader()
{
var shader = root.Q<ObjectField>("ShaderOverride");
shader.SetValueWithoutNotify(avatarConfigTarget.Shader);
shader.RegisterValueChangedCallback(x =>
{
avatarConfigTarget.Shader = (Shader) x.newValue;
Save();
SetupShader();
}
);
var shaderPropertiesContainer = root.Q<VisualElement>("ShaderProperties");
shaderPropertiesContainer.Clear();
shaderPropertiesContainer.style.display = DisplayStyle.Flex;
shaderPropertiesContainer.style.flexDirection = FlexDirection.Column;
if (avatarConfigTarget.Shader == null)
{
shaderPropertiesContainer.style.display = DisplayStyle.None;
}
else
{
shaderPropertiesContainer.style.display = DisplayStyle.Flex;
shaderPropertiesContainer.style.marginTop = 10;
shaderPropertiesContainer.style.left = 10;
shaderPropertiesContainer.style.right = 10;
var titleRowContainer = new VisualElement();
titleRowContainer.style.flexDirection = FlexDirection.Row;
titleRowContainer.style.marginBottom = 7;
titleRowContainer.style.marginTop = 7;
titleRowContainer.style.left = 10;
titleRowContainer.style.right = 10;
var sourceTitleField = new Label("Source Property")
{
style =
{
width = 200, unityFontStyleAndWeight = FontStyle.Bold, // Make the text bold
unityTextAlign = TextAnchor.MiddleLeft
}
};
titleRowContainer.Add(sourceTitleField);
var targetTitleField = new Label("Target Property")
{
style = { width = 200, marginRight = 10, flexGrow = 0.8f, unityFontStyleAndWeight = FontStyle.Bold, }
};
titleRowContainer.Add(targetTitleField);
var typeTitleField = new Label("Type")
{
style = { width = 70, alignSelf = Align.FlexEnd, unityFontStyleAndWeight = FontStyle.Bold, }
};
titleRowContainer.Add(typeTitleField);
shaderPropertiesContainer.Add(titleRowContainer);
for (int i = 0; i < shaderPropertyMappingList.arraySize; i++)
{
SerializedProperty mapping = shaderPropertyMappingList.GetArrayElementAtIndex(i);
var propertyContainer = new VisualElement();
propertyContainer.style.flexDirection = FlexDirection.Column;
//propertyContainer.style.marginBottom = 10;
var horizontalContainer = new VisualElement();
horizontalContainer.style.flexDirection = FlexDirection.Row;
horizontalContainer.style.marginBottom = 7;
horizontalContainer.style.marginTop = 7;
horizontalContainer.style.left = 10;
horizontalContainer.style.right = 10;
// Alternating background colors
propertyContainer.style.backgroundColor = i % 2 == 0 ? new StyleColor(new Color(0.25f, 0.25f, 0.25f)) : new StyleColor(new Color(0.3f, 0.3f, 0.3f));
var sourcePropertyField = new Label(mapping.FindPropertyRelative("SourceProperty").stringValue)
{
style =
{
width = 200, unityFontStyleAndWeight = FontStyle.Bold, // Make the text bold
unityTextAlign = TextAnchor.MiddleLeft
}
};
horizontalContainer.Add(sourcePropertyField);
var targetPropertyField = new TextField
{
value = mapping.FindPropertyRelative("TargetProperty").stringValue,
//style = { flexGrow = 1, marginTop = 5 }
style = { width = 200, marginRight = 10, flexGrow = 0.8f }
};
targetPropertyField.RegisterValueChangedCallback(evt =>
{
mapping.FindPropertyRelative("TargetProperty").stringValue = evt.newValue;
Save();
});
horizontalContainer.Add(targetPropertyField);
var propertyTypeField = new EnumField((ShaderPropertyType) mapping.FindPropertyRelative("Type").enumValueIndex)
{
style = { width = 70, alignSelf = Align.FlexEnd }
};
propertyTypeField.RegisterValueChangedCallback(evt =>
{
mapping.FindPropertyRelative("Type").enumValueIndex = (int) (ShaderPropertyType) evt.newValue;
Save();
});
horizontalContainer.Add(propertyTypeField);
propertyContainer.Add(horizontalContainer);
shaderPropertiesContainer.Add(propertyContainer);
}
}
}
private void SetupMorphTargets()
{
morphTargetLabels = AvatarMorphTarget.MorphTargetAvatarAPI.Select(x => new Label(x)).ToList();
morphTargetsParentVisualElement = new Dictionary<VisualElement, string>();
selectedMorphTargets = root.Q<VisualElement>("SelectedMorphTargets");
for (var i = 0; i < avatarConfigTarget.MorphTargets.Count; i++)
{
var defaultIndex = AvatarMorphTarget.MorphTargetAvatarAPI.IndexOf(avatarConfigTarget.MorphTargets[i]);
CreateNewElement(defaultIndex);
}
var addButton = root.Q<Button>("AddButton");
addButton.clicked += OnAddButtonClicked;
}
private void OnAddButtonClicked()
{
Undo.RecordObject(avatarConfigTarget, ADD_MORPH_TARGET);
avatarConfigTarget.MorphTargets.Add(AvatarMorphTarget.MorphTargetAvatarAPI[0]);
EditorUtility.SetDirty(avatarConfigTarget);
CreateNewElement(0);
}
private void CreateNewElement(int popFieldDefaultIndex)
{
var parent = new VisualElement();
parent.style.flexDirection = new StyleEnum<FlexDirection>(FlexDirection.Row);
parent.style.justifyContent = new StyleEnum<Justify>(Justify.SpaceBetween);
morphTargetsParentVisualElement.Add(parent, AvatarMorphTarget.MorphTargetAvatarAPI[popFieldDefaultIndex]);
parent.Add(CreatePopupField(popFieldDefaultIndex, parent));
parent.Add(CreateRemoveButton(parent));
selectedMorphTargets.Add(parent);
}
private PopupField<Label> CreatePopupField(int defaultIndex, VisualElement parent)
{
return new PopupField<Label>(string.Empty,
morphTargetLabels,
defaultIndex,
x =>
{
avatarConfigTarget.MorphTargets[GetIndex(morphTargetsParentVisualElement[parent])] = x.text;
morphTargetsParentVisualElement[parent] = x.text;
return x.text;
},
x => x.text);
}
private VisualElement CreateRemoveButton(VisualElement parent)
{
var removeButton = new Button(() =>
{
Undo.RecordObject(avatarConfigTarget, DELETE_MORPH_TARGET);
avatarConfigTarget.MorphTargets.RemoveAt(GetIndex(morphTargetsParentVisualElement[parent]));
selectedMorphTargets.Remove(parent);
EditorUtility.SetDirty(avatarConfigTarget);
});
removeButton.text = REMOVE_BUTTON_TEXT;
return removeButton;
}
private int GetIndex(string morphTarget)
{
return avatarConfigTarget.MorphTargets.FindIndex(x => x == morphTarget);
}
}
}
@@ -0,0 +1,20 @@
fileFormatVersion: 2
guid: dd70400e8b2b4c20bfe2f9bc47844cff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- visualTreeAsset: {fileID: 9197481963319205126, guid: 166ba78a57a90ca4abc5779ed8901042,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/CustomEditors/AvatarConfigEditor.cs
uploadId: 704624
@@ -0,0 +1,22 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<uie:EnumField label="Lod" value="High" type="ReadyPlayerMe.Core.Lod, ReadyPlayerMe.Core" name="Lod" />
<uie:EnumField label="Pose" value="APose" type="ReadyPlayerMe.Core.Pose, ReadyPlayerMe.Core" name="Pose" />
<ui:Toggle label="Use Hands" name="UseHands" value="false" style="margin-left: 3px; height: 16px; margin-top: 3px;" />
<uie:EnumField label="TextureAtlas" value="High" type="ReadyPlayerMe.Core.TextureAtlas, ReadyPlayerMe.Core" name="TextureAtlas" />
<ui:SliderInt picking-mode="Ignore" label="TextureSizeLimit" value="0" high-value="1024" low-value="256" show-input-field="true" name="TextureSizeLimit" />
<ui:Foldout text="Texture Channel" name="TextureChannel" value="false" style="flex-direction: column; margin-left: 4px; flex-grow: 0; margin-right: 4px; margin-top: 4px; align-items: stretch; justify-content: space-between; flex-shrink: 0;">
<ui:ListView focusable="true" reorderable="true" show-border="true" show-alternating-row-backgrounds="All" style="height: auto; flex-shrink: 0; flex-grow: 0; justify-content: flex-start; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px;" />
</ui:Foldout>
<ui:VisualElement name="CustomShader" style="border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgba(113, 109, 109, 255); border-right-color: rgba(113, 109, 109, 255); border-top-color: rgba(113, 109, 109, 255); border-bottom-color: rgba(113, 109, 109, 255);">
<uie:ObjectField label="Shader Override" type="UnityEngine.Shader, UnityEngine.CoreModule" name="ShaderOverride" />
<ui:VisualElement name="ShaderProperties" style="flex-grow: 1; margin-left: 5px;" />
</ui:VisualElement>
<ui:Foldout text="Optimization Packages" name="OptimizationPackages" value="false" style="flex-shrink: 0; margin-top: 4px; margin-left: 4px; margin-right: 4px;">
<ui:Toggle label="Use Draco Compression" name="UseDracoCompression" style="flex-direction: row; align-items: center; justify-content: flex-start; margin-left: 3px; margin-top: 3px;" />
<ui:Toggle label="Use Mesh Opt Compression" name="UseMeshOptCompression" style="margin-left: 3px; margin-top: 3px; align-items: center; flex-direction: row; flex-grow: 0; flex-shrink: 0; flex-wrap: nowrap; position: relative; overflow: hidden; opacity: 1;" />
</ui:Foldout>
<ui:Foldout text="Morph Targets" name="MorphTargets" value="false" style="margin-left: 4px; margin-right: 4px; margin-top: 4px; margin-bottom: 1px;">
<ui:VisualElement name="SelectedMorphTargets" style="flex-grow: 0; margin-top: 5px; -unity-text-outline-width: 0;" />
<ui:Button text="Add" display-tooltip-when-elided="true" name="AddButton" style="margin-top: 5px;" />
</ui:Foldout>
</ui:UXML>
@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: 166ba78a57a90ca4abc5779ed8901042
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/CustomEditors/AvatarConfigEditor.uxml
uploadId: 704624
@@ -0,0 +1,27 @@
using UnityEditor;
namespace ReadyPlayerMe.Core.Editor
{
[CustomEditor(typeof(AvatarData))]
public class AvatarDataEditor : UnityEditor.Editor
{
private SerializedProperty avatarIdProperty;
private SerializedProperty avatarMetadataProperty;
private void OnEnable()
{
var avatarData = (AvatarData) target;
avatarIdProperty = serializedObject.FindProperty(nameof(avatarData.AvatarId));
avatarMetadataProperty = serializedObject.FindProperty(nameof(avatarData.AvatarMetadata));
}
public override void OnInspectorGUI()
{
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.PropertyField(avatarIdProperty);
EditorGUILayout.PropertyField(avatarMetadataProperty);
EditorGUI.EndDisabledGroup();
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 30e5b5d4cbc84b689f1b98490cc2a57b
timeCreated: 1676906312
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/CustomEditors/AvatarDataEditor.cs
uploadId: 704624
@@ -0,0 +1,46 @@
using UnityEditor;
using UnityEngine;
namespace ReadyPlayerMe.Core.Editor
{
[CustomEditor(typeof(EyeAnimationHandler))]
public class EyeAnimationHandlerEditor : UnityEditor.Editor
{
private const string BLINK_DURATION = "blinkDuration";
private const string BLINK_INTERVAL = "blinkInterval";
private readonly GUIContent blinkSpeedLabel =
new GUIContent("Blink Duration", "Effects the duration of the avatar blink animation in seconds.");
private readonly GUIContent blinkIntervalLabel =
new GUIContent("Blink Interval", "Effects the amount of time in between each blink in seconds..");
private SerializedProperty blinkDuration;
private SerializedProperty blinkInterval;
public override void OnInspectorGUI()
{
DrawPropertyField(blinkDuration, blinkSpeedLabel);
DrawPropertyField(blinkInterval, blinkIntervalLabel);
}
private void OnEnable()
{
blinkDuration = serializedObject.FindProperty(BLINK_DURATION);
blinkInterval = serializedObject.FindProperty(BLINK_INTERVAL);
}
private void DrawPropertyField(SerializedProperty property, GUIContent content)
{
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(property, content);
if (EditorGUI.EndChangeCheck() && Application.isPlaying)
{
(target as EyeAnimationHandler)?.Initialize();
}
serializedObject.ApplyModifiedProperties();
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 02b38ee26065cb443adf628c0b8ded61
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/CustomEditors/EyeAnimationHandlerEditor.cs
uploadId: 704624
@@ -0,0 +1,73 @@
using UnityEditor;
using UnityEngine;
namespace ReadyPlayerMe.Core.Editor
{
[CustomEditor(typeof(VoiceHandler))]
public class VoiceHandlerEditor : UnityEditor.Editor
{
private const string AUDIO_CLIP = "AudioClip";
private const string PROPERTY_PATH = "AudioSource";
private const string AUDIO_SOURCE = PROPERTY_PATH;
private const string AUDIO_PROVIDER = "AudioProvider";
private const string MICROPHONE_IS_NOT_SUPPORTED_IN_WEBGL = "Microphone is not supported in WebGL.";
private const string TEST_AUDIO_CLIP_PLAY_MODE = "Test Audio Clip [Play Mode]";
private readonly GUIContent audioClipLabel = new GUIContent(AUDIO_CLIP, "AudioClip to play.");
private readonly GUIContent audioSourceLabel = new GUIContent(AUDIO_SOURCE,
"AudioSource that will play the audio. If not assigned spawns on the avatar root object.");
private readonly GUIContent audioProviderLabel =
new GUIContent(AUDIO_PROVIDER, "Selection for source of the audio.");
private SerializedProperty audioClip;
private SerializedProperty audioSource;
private SerializedProperty audioProvider;
public override void OnInspectorGUI()
{
DrawPropertyField(audioProvider, audioProviderLabel);
DrawPropertyField(audioSource, audioSourceLabel);
if (audioProvider.intValue == (int) AudioProviderType.AudioClip)
{
DrawPropertyField(audioClip, audioClipLabel);
GUI.enabled = Application.isPlaying;
if (GUILayout.Button(TEST_AUDIO_CLIP_PLAY_MODE))
{
((VoiceHandler) target).PlayCurrentAudioClip();
}
GUI.enabled = true;
}
#if UNITY_WEBGL
if (audioProvider.intValue == (int) AudioProviderType.Microphone)
{
EditorGUILayout.HelpBox(MICROPHONE_IS_NOT_SUPPORTED_IN_WEBGL, MessageType.Warning);
}
#endif
}
private void OnEnable()
{
audioClip = serializedObject.FindProperty(AUDIO_CLIP);
audioSource = serializedObject.FindProperty(AUDIO_SOURCE);
audioProvider = serializedObject.FindProperty(AUDIO_PROVIDER);
}
private void DrawPropertyField(SerializedProperty property, GUIContent content)
{
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(property, content);
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
((VoiceHandler) target).InitializeAudio();
}
}
}
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: 56f2c5f87e6c33748843fd099b9e2242
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/CustomEditors/VoiceHandlerEditor.cs
uploadId: 704624
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bd8d777b90a04f7ab091ca8efd1b0b63
timeCreated: 1673349421
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5bd53f8c2f141b74393738962a77da0f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,135 @@
using ReadyPlayerMe.Core.Analytics;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace ReadyPlayerMe.Core.Editor
{
public class AvatarLoaderEditor : EditorWindow
{
private const string TAG = nameof(AvatarLoaderEditor);
private const string AVATAR_LOADER = "Avatar Loader";
private const string LOAD_AVATAR_BUTTON = "LoadAvatarButton";
private const string HEADER_LABEL = "HeaderLabel";
private const string USE_EYE_ANIMATIONS_TOGGLE = "UseEyeAnimationsToggle";
private const string USE_VOICE_TO_ANIMATION_TOGGLE = "UseVoiceToAnimationToggle";
private const string VOICE_TO_ANIM_SAVE_KEY = "VoiceToAnimSaveKey";
private const string EYE_ANIMATION_SAVE_KEY = "EyeAnimationSaveKey";
private const string MODEL_CACHING_SAVE_KEY = "ModelCachingSaveKey";
[SerializeField] private VisualTreeAsset visualTreeAsset;
private double startTime;
private AvatarLoaderSettings avatarLoaderSettings;
private bool useEyeAnimations;
private bool useVoiceToAnim;
[MenuItem("Tools/Ready Player Me/Avatar Loader", priority = 1)]
public static void ShowWindow()
{
var window = GetWindow<AvatarLoaderEditor>();
window.titleContent = new GUIContent(AVATAR_LOADER);
window.minSize = new Vector2(500, 300);
}
public void CreateGUI()
{
visualTreeAsset.CloneTree(rootVisualElement);
if (EditorPrefs.GetBool(MODEL_CACHING_SAVE_KEY)) EditorPrefs.SetBool(MODEL_CACHING_SAVE_KEY, false);
var headerLabel = rootVisualElement.Q<Label>(HEADER_LABEL);
headerLabel.text = AVATAR_LOADER;
var useEyeAnimationsToggle = rootVisualElement.Q<Toggle>(USE_EYE_ANIMATIONS_TOGGLE);
useEyeAnimations = EditorPrefs.GetBool(EYE_ANIMATION_SAVE_KEY);
useEyeAnimationsToggle.value = useEyeAnimations;
useEyeAnimationsToggle.RegisterCallback<ChangeEvent<bool>>(evt =>
{
useEyeAnimations = evt.newValue;
EditorPrefs.SetBool(EYE_ANIMATION_SAVE_KEY, useEyeAnimations);
});
var useVoiceToAnimToggle = rootVisualElement.Q<Toggle>(USE_VOICE_TO_ANIMATION_TOGGLE);
useVoiceToAnim = EditorPrefs.GetBool(VOICE_TO_ANIM_SAVE_KEY);
useVoiceToAnimToggle.value = useVoiceToAnim;
useVoiceToAnimToggle.RegisterCallback<ChangeEvent<bool>>(evt =>
{
useVoiceToAnim = evt.newValue;
EditorPrefs.SetBool(VOICE_TO_ANIM_SAVE_KEY, useVoiceToAnim);
});
var avatarLoader = rootVisualElement.Q<Button>(LOAD_AVATAR_BUTTON);
var urlField = rootVisualElement.Q<AvatarUrlTemplate>();
avatarLoader.clicked += () =>
{
if (urlField.TryGetUrl(out var url))
{
LoadAvatar(url);
}
};
}
private void LoadAvatar(string url)
{
startTime = EditorApplication.timeSinceStartup;
AnalyticsEditorLogger.EventLogger.LogLoadAvatarFromDialog(url, useEyeAnimations, useVoiceToAnim);
if (avatarLoaderSettings == null)
{
avatarLoaderSettings = AvatarLoaderSettings.LoadSettings();
}
var avatarLoader = new AvatarObjectLoader();
avatarLoader.OnFailed += Failed;
avatarLoader.OnCompleted += Completed;
avatarLoader.OperationCompleted += OnOperationCompleted;
if (avatarLoaderSettings != null)
{
avatarLoader.AvatarConfig = avatarLoaderSettings.AvatarConfig;
if (avatarLoaderSettings.GLTFDeferAgent != null)
{
avatarLoader.GLTFDeferAgent = avatarLoaderSettings.GLTFDeferAgent;
}
}
avatarLoader.LoadAvatar(url);
}
private void OnOperationCompleted(object sender, IOperation<AvatarContext> e)
{
if (e.GetType() == typeof(MetadataDownloader))
{
AnalyticsEditorLogger.EventLogger.LogMetadataDownloaded(EditorApplication.timeSinceStartup - startTime);
}
}
private void Failed(object sender, FailureEventArgs args)
{
Debug.LogError($"{args.Type} - {args.Message}");
}
private void Completed(object sender, CompletionEventArgs args)
{
AnalyticsEditorLogger.EventLogger.LogAvatarLoaded(EditorApplication.timeSinceStartup - startTime);
if (avatarLoaderSettings == null)
{
avatarLoaderSettings = AvatarLoaderSettings.LoadSettings();
}
var paramHash = AvatarCache.GetAvatarConfigurationHash(avatarLoaderSettings.AvatarConfig);
var path = $"{DirectoryUtility.GetRelativeProjectPath(args.Avatar.name, paramHash)}/{args.Avatar.name}";
if (!avatarLoaderSettings.AvatarCachingEnabled)
{
SDKLogger.LogWarning(TAG, "Enable Avatar Caching to generate a prefab in the project folder.");
return;
}
var avatar = PrefabHelper.CreateAvatarPrefab(args.Metadata, path, avatarConfig: avatarLoaderSettings.AvatarConfig);
if (useEyeAnimations) avatar.AddComponent<EyeAnimationHandler>();
if (useVoiceToAnim) avatar.AddComponent<VoiceHandler>();
DestroyImmediate(args.Avatar, true);
Selection.activeObject = avatar;
}
}
}
@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: 42d4f7af0c237ce4b962a3966fcde2ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- visualTreeAsset: {fileID: 9197481963319205126, guid: 9c9fb1a8c3e120d42b59955126dc5cc1,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/AvatarLoaderEditor/AvatarLoaderEditor.cs
uploadId: 704624
@@ -0,0 +1,14 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
<ui:Template name="HeaderTemplate" src="../Templates/HeaderTemplate.uxml" />
<Style src="../CommonStyle.uss" />
<ui:VisualElement name="ContentWrapper" style="align-items: center; width: 500px; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: auto;">
<ui:Instance template="HeaderTemplate" name="HeaderTemplate" style="flex-shrink: 0;" />
<ReadyPlayerMe.Core.Editor.AvatarUrlTemplate style="flex-shrink: 0; width: 500px;" />
<ui:VisualElement name="Extras" style="flex-shrink: 0; flex-direction: column; align-items: flex-start; justify-content: flex-start; align-self: stretch;">
<ui:Label text="Extras" display-tooltip-when-elided="true" class="headingText" />
<ui:Toggle label="Use Eye Animations" name="UseEyeAnimationsToggle" style="flex-direction: row-reverse; margin-left: 15px; margin-top: 10px;" />
<ui:Toggle label="Use Voice To Animation" name="UseVoiceToAnimationToggle" style="flex-direction: row-reverse; margin-left: 15px; margin-top: 10px;" />
</ui:VisualElement>
<ui:Button text="Load Avatar into the Current Scene" display-tooltip-when-elided="true" name="LoadAvatarButton" style="margin-top: 10px; margin-left: 15px; margin-right: 15px; font-size: 16px; -unity-font-style: bold; height: 30px; -unity-text-align: middle-center; white-space: nowrap; margin-bottom: 10px; width: 470px;" />
</ui:VisualElement>
</ui:UXML>
@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: 9c9fb1a8c3e120d42b59955126dc5cc1
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/AvatarLoaderEditor/AvatarLoaderEditorWindow.uxml
uploadId: 704624
@@ -0,0 +1,56 @@
using UnityEditor;
namespace ReadyPlayerMe.Core.Editor
{
public static class AvatarLoaderSettingsHelper
{
public static AvatarLoaderSettings AvatarLoaderSettings
{
get
{
if (avatarLoaderSettings == null)
{
avatarLoaderSettings = AvatarLoaderSettings.LoadSettings();
}
return avatarLoaderSettings;
}
}
private static AvatarLoaderSettings avatarLoaderSettings;
public static void SaveAvatarConfig(AvatarConfig avatarConfig)
{
if (avatarLoaderSettings != null && avatarLoaderSettings.AvatarConfig != avatarConfig)
{
avatarLoaderSettings.AvatarConfig = avatarConfig;
SaveAvatarLoaderSettings();
}
}
public static void SaveDeferAgent(GLTFDeferAgent deferAgent)
{
if (avatarLoaderSettings != null && avatarLoaderSettings.GLTFDeferAgent != deferAgent)
{
avatarLoaderSettings.GLTFDeferAgent = deferAgent;
SaveAvatarLoaderSettings();
}
}
public static void SetAvatarCaching(bool enable)
{
if (avatarLoaderSettings != null)
{
avatarLoaderSettings.AvatarCachingEnabled = enable;
SaveAvatarLoaderSettings();
}
}
private static void SaveAvatarLoaderSettings()
{
EditorUtility.SetDirty(avatarLoaderSettings);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 2e9df9df699f4bb09c162c7948503583
timeCreated: 1686078044
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/AvatarLoaderSettingsHelper.cs
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6e97a78112f684e40ad730948b73896b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,47 @@
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace ReadyPlayerMe.Core.Editor
{
public class BreakingChangeDialog : EditorWindow
{
private const string MIGRATION_GUIDE_URL = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/troubleshooting/updating-from-earlier-versions";
private const string TITLE = "Update Packages";
[SerializeField] private VisualTreeAsset visualTreeAsset;
private static Action updateClicked;
public static void ShowDialog(Action onUpdate)
{
updateClicked = onUpdate;
var window = GetWindow<BreakingChangeDialog>();
window.titleContent = new GUIContent(TITLE);
window.minSize = new Vector2(500, 140);
window.maxSize = new Vector2(500, 140);
window.ShowModalUtility();
}
public void CreateGUI()
{
visualTreeAsset.CloneTree(rootVisualElement);
var migrationLink = rootVisualElement.Q<Label>("MigrationLink");
migrationLink.RegisterCallback<MouseUpEvent>(x =>
{
Application.OpenURL(MIGRATION_GUIDE_URL);
});
rootVisualElement.Q<Button>("UpdateButton").clicked += () =>
{
updateClicked?.Invoke();
Close();
};
rootVisualElement.Q<Button>("CancelButton").clicked += Close;
}
}
}
@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: a33436e71dc6be2449976c3e84fa2b80
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- visualTreeAsset: {fileID: 9197481963319205126, guid: 26fd6ad3d3a5b8b40b21885331e8c518,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/BreakingChangeDialog/BreakingChangeDialog.cs
uploadId: 704624
@@ -0,0 +1,16 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<Style src="../CommonStyle.uss" />
<ui:VisualElement style="flex-direction: row; align-items: stretch; justify-content: flex-start; margin-left: 20px; margin-right: 20px; margin-top: 20px; margin-bottom: 20px; flex-shrink: 0;">
<ui:VisualElement name="IconContainer" style="width: 60px; height: 60px; flex-direction: row; align-items: center; justify-content: center; background-color: rgb(0, 0, 0);">
<ui:VisualElement name="Icon" style="background-image: resource(&apos;rpm_logo&apos;); width: 50px; height: 50px; flex-direction: row; flex-shrink: 0; -unity-background-scale-mode: scale-to-fit; background-color: rgba(0, 0, 0, 0);" />
</ui:VisualElement>
<ui:VisualElement name="Description" style="align-items: flex-start; justify-content: center; margin-left: 10px; flex-shrink: 0;">
<ui:Label text="This is a breaking change! Do you still want to update? " name="Text" style="margin-top: 0; margin-right: 0; margin-left: 0; margin-bottom: 0; white-space: normal; -unity-text-align: middle-left;" />
<ui:Label text="Link to Migration Guide" name="MigrationLink" class="link" style="margin-top: 5px; margin-right: 0; margin-left: 0; margin-bottom: 0; white-space: normal; -unity-text-align: middle-left; color: rgb(0, 104, 255);" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="Buttons" style="flex-direction: row-reverse; padding-right: 10px; padding-left: 10px; padding-top: 10px; padding-bottom: 10px; flex-shrink: 0; height: 44px;">
<ui:Button text="Cancel" display-tooltip-when-elided="true" name="CancelButton" />
<ui:Button text="Update" display-tooltip-when-elided="true" name="UpdateButton" style="white-space: nowrap;" />
</ui:VisualElement>
</ui:UXML>
@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: 26fd6ad3d3a5b8b40b21885331e8c518
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/BreakingChangeDialog/BreakingChangeDialog.uxml
uploadId: 704624
@@ -0,0 +1,34 @@
.headingText {
-unity-font-style: bold;
font-size: 16px;
margin-top: 0;
margin-left: 15px;
justify-content: flex-start;
flex-direction: row;
align-items: flex-start;
-unity-text-align: upper-left;
white-space: nowrap;
border-right-width: 2px;
}
.heading {
flex-direction: row;
align-items: center;
justify-content: flex-start;
margin-top: 10px;
margin-bottom: 10px;
flex-shrink: 0;
-unity-font-style: normal;
}
.unity-toggle__label {
margin-left: 10px;
}
.box {
background-color: var(--unity-colors-alternated_rows-background);
}
.link{
cursor: link;
}
@@ -0,0 +1,18 @@
fileFormatVersion: 2
guid: af10d225241bded4188e82d92db9230f
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/CommonStyle.uss
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0ad6dcb1d01ac3141b39cd0999f16412
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,127 @@
using System.IO;
using ReadyPlayerMe.Core.Analytics;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEngine;
using UnityEngine.UIElements;
namespace ReadyPlayerMe.Core.Editor
{
public class IntegrationGuide : EditorWindow
{
private const string INTEGRATION_GUIDE = "Integration Guide";
private const string HEADER_LABEL = "HeaderLabel";
private const string LOAD_AVATARS_URL = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/load-avatars";
private const string ADD_ANIMATION_URL = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/animations";
private const string AVATAR_CREATOR_URL = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/avatar-creator";
private const string OPTIMIZE_PERFORMANCE_URL = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/optimize";
private const string QUICK_START = "QuickStart";
private const string LOAD_AVATARS = "LoadAvatars";
private const string ADD_ANIMATIONS = "AddAnimations";
private const string INTEGRATE_AVATAR_CREATOR = "IntegrateAvatarCreator";
private const string OPTIMIZE_THE_PERFORMANCE = "OptimizeThePerformance";
private const string CORE_PACKAGE = "com.readyplayerme.core";
private const string QUICKSTART_SAMPLE_NAME = "QuickStart";
private const string AVATAR_CREATOR_SAMPLE_NAME = "AvatarCreatorSamples";
private const string AVATAR_CREATOR_SAMPLE_SCENE_PATH = "AvatarCreatorElements/Scenes/AvatarCreatorElements";
private const string SAMPLES_FOLDER_PATH = "Assets/Ready Player Me/Core/Samples";
[SerializeField] private VisualTreeAsset visualTreeAsset;
[MenuItem("Tools/Ready Player Me/Integration Guide", priority = 12)]
public static void ShowWindow()
{
var window = GetWindow<IntegrationGuide>();
window.titleContent = new GUIContent(INTEGRATION_GUIDE);
window.minSize = new Vector2(500, 530);
AnalyticsEditorLogger.EventLogger.LogOpenIntegrationGuide();
}
public void CreateGUI()
{
visualTreeAsset.CloneTree(rootVisualElement);
var headerLabel = rootVisualElement.Q<Label>(HEADER_LABEL);
headerLabel.text = INTEGRATION_GUIDE;
RegisterButtons();
}
private void RegisterButtons()
{
rootVisualElement.Q<VisualElement>(QUICK_START).Q<Button>().clicked += () =>
{
AnalyticsEditorLogger.EventLogger.LogLoadQuickStartScene();
LoadAndOpenSample(QUICKSTART_SAMPLE_NAME, QUICKSTART_SAMPLE_NAME);
};
rootVisualElement.Q<VisualElement>(LOAD_AVATARS).Q<Button>().clicked += () =>
{
AnalyticsEditorLogger.EventLogger.LogOpenAvatarDocumentation();
OpenDocumentation(LOAD_AVATARS_URL);
};
rootVisualElement.Q<VisualElement>(ADD_ANIMATIONS).Q<Button>().clicked += () =>
{
AnalyticsEditorLogger.EventLogger.LogOpenAnimationDocumentation();
OpenDocumentation(ADD_ANIMATION_URL);
};
rootVisualElement.Q<VisualElement>(INTEGRATE_AVATAR_CREATOR).Q<Button>("SeeDocsButton").clicked += () =>
{
AnalyticsEditorLogger.EventLogger.LogOpenAvatarCreatorDocumentation();
OpenDocumentation(AVATAR_CREATOR_URL);
};
rootVisualElement.Q<VisualElement>(INTEGRATE_AVATAR_CREATOR).Q<Button>("LoadSampleSceneButton").clicked += () =>
{
AnalyticsEditorLogger.EventLogger.LogAvatarCreatorSampleImported();
LoadAndOpenSample(AVATAR_CREATOR_SAMPLE_NAME, AVATAR_CREATOR_SAMPLE_SCENE_PATH);
};
rootVisualElement.Q<VisualElement>(OPTIMIZE_THE_PERFORMANCE).Q<Button>().clicked += () =>
{
AnalyticsEditorLogger.EventLogger.LogOpenOptimizationDocumentation();
OpenDocumentation(OPTIMIZE_PERFORMANCE_URL);
};
}
private void LoadAndOpenSample(string sampleName, string scenePath)
{
if (LoadFromAssetsFolder(sampleName, scenePath))
{
return;
}
var sampleLoader = new SampleLoader();
if (sampleLoader.Load(CORE_PACKAGE, sampleName))
{
sampleLoader.OpenScene(scenePath);
return;
}
EditorUtility.DisplayDialog(INTEGRATION_GUIDE, $"No sample with name {sampleName} found.", "OK");
}
private bool LoadFromAssetsFolder(string sampleName, string scenePath)
{
var version = ApplicationData.GetData().UnityVersion;
var folderPath = $"{SAMPLES_FOLDER_PATH}/{sampleName}";
if (!Directory.Exists(folderPath))
{
folderPath = $"{SAMPLES_FOLDER_PATH}/{version}/{sampleName}";
}
if (!Directory.Exists(folderPath)) return false;
var fullScenePath = $"{folderPath}/{scenePath}.unity";
if (!File.Exists(fullScenePath)) return false;
EditorSceneManager.OpenScene(fullScenePath);
return true;
}
private void OpenDocumentation(string link)
{
Application.OpenURL(link);
}
}
}
@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: 9ec6b00e77be2a246b913192a91b1850
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- visualTreeAsset: {fileID: 9197481963319205126, guid: 4a4f82d8946b5f74b88cd2a924583d70,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/IntegrationGuide/IntegrationGuide.cs
uploadId: 704624
@@ -0,0 +1,39 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<ui:Template name="HeaderTemplate" src="../Templates/HeaderTemplate.uxml" />
<Style src="../CommonStyle.uss" />
<ui:VisualElement name="ContentWrapper" style="width: 500px; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: auto; align-items: center;">
<ui:Instance template="HeaderTemplate" name="HeaderTemplate" />
<ui:VisualElement name="QuickStart" class="box" style="flex-shrink: 0; width: 470px; -unity-background-scale-mode: stretch-to-fill; margin-left: 15px; margin-right: 15px; margin-top: 15px; margin-bottom: 0; flex-direction: column; align-items: flex-start; justify-content: space-around;">
<ui:Label text="Quickstart Scene" display-tooltip-when-elided="true" name="Heading" class="headingText" style="margin-left: 5px; margin-bottom: 10px; margin-top: 10px; margin-right: 5px; font-size: 14px;" />
<ui:Label text="See your personal avatar in action. Load the Unity scene, paste your avatar-url and load and control the avatar in playmode." display-tooltip-when-elided="true" name="Description" style="white-space: normal; margin-left: 5px; margin-right: 5px;" />
<ui:Button text="Load Quickstart Scene" display-tooltip-when-elided="true" style="-unity-text-align: middle-center; white-space: nowrap; flex-direction: row-reverse; align-items: auto; justify-content: flex-start; border-left-width: 0; border-right-width: 0; border-top-width: 0; border-bottom-width: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; padding-left: 5px; padding-right: 5px; padding-top: 5px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px; margin-right: 5px; margin-left: 5px;" />
</ui:VisualElement>
<ui:VisualElement name="FirstRow" style="flex-direction: row; align-items: center; justify-content: space-between; margin-left: 0; margin-right: 0; width: 500px; flex-shrink: 0;">
<ui:VisualElement name="LoadAvatars" class="box" style="flex-shrink: 0; -unity-background-scale-mode: stretch-to-fill; margin-left: 15px; margin-right: 7.5px; margin-top: 15px; margin-bottom: 15px; flex-direction: column; align-items: flex-start; justify-content: space-around; flex-grow: 0; width: 227.5px; height: 135px;">
<ui:Label text="Load Avatars" display-tooltip-when-elided="true" name="Heading" class="headingText" style="margin-left: 5px; margin-bottom: 10px; margin-top: 10px; margin-right: 5px; font-size: 14px;" />
<ui:Label text="Learn how to load 3D and 2D renders of Avatars at runtime or as NPCs in your project." display-tooltip-when-elided="true" name="Description" style="white-space: normal; margin-left: 5px; margin-right: 5px; -unity-text-align: upper-left;" />
<ui:Button text="See Docs" display-tooltip-when-elided="true" style="-unity-text-align: middle-center; white-space: nowrap; flex-direction: row-reverse; align-items: auto; justify-content: flex-start; border-left-width: 0; border-right-width: 0; border-top-width: 0; border-bottom-width: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; padding-left: 5px; padding-right: 5px; padding-top: 5px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px; margin-right: 5px; margin-left: 5px;" />
</ui:VisualElement>
<ui:VisualElement name="AddAnimations" class="box" style="flex-shrink: 1; -unity-background-scale-mode: stretch-to-fill; margin-left: 7.5px; margin-right: 15px; margin-top: 15px; margin-bottom: 15px; flex-direction: column; align-items: flex-start; justify-content: space-around; width: 227.5px; height: 135px;">
<ui:Label text="Add Animations" display-tooltip-when-elided="true" name="Heading" class="headingText" style="margin-left: 5px; margin-bottom: 10px; margin-top: 10px; margin-right: 5px; font-size: 14px;" />
<ui:Label text="Learn how to animate Ready Player Me avatars and use the free animation pack." display-tooltip-when-elided="true" name="Description" style="white-space: normal; margin-left: 5px; margin-right: 5px;" />
<ui:Button text="See Docs" display-tooltip-when-elided="true" style="-unity-text-align: middle-center; white-space: nowrap; flex-direction: row-reverse; align-items: auto; justify-content: flex-start; border-left-width: 0; border-right-width: 0; border-top-width: 0; border-bottom-width: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; padding-left: 5px; padding-right: 5px; padding-top: 5px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px; margin-right: 5px; margin-left: 5px;" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="SecondRow" style="flex-direction: row; align-items: center; justify-content: space-between; margin-left: 0; margin-right: 0; width: 500px; flex-shrink: 0;">
<ui:VisualElement name="IntegrateAvatarCreator" class="box" style="flex-shrink: 0; -unity-background-scale-mode: stretch-to-fill; margin-left: 15px; margin-right: 7.5px; margin-top: 0; margin-bottom: 15px; flex-direction: column; align-items: flex-start; justify-content: space-around; width: 227.5px; height: 135px;">
<ui:Label text="Integrate the Avatar Creator" display-tooltip-when-elided="true" name="Heading" class="headingText" style="margin-left: 5px; margin-bottom: 10px; margin-top: 10px; margin-right: 5px; font-size: 14px;" />
<ui:Label text="Learn how to integrate the avatar creator in your app or game." display-tooltip-when-elided="true" name="Description" style="white-space: normal; margin-left: 5px; margin-right: 5px; -unity-text-align: upper-left;" />
<ui:VisualElement name="Buttons" style="flex-direction: row; align-items: stretch; justify-content: flex-start; flex-shrink: 0; margin-bottom: 0; margin-top: 0;">
<ui:Button text="See Docs" display-tooltip-when-elided="true" name="SeeDocsButton" style="-unity-text-align: middle-center; white-space: nowrap; flex-direction: row-reverse; align-items: auto; justify-content: flex-start; border-left-width: 0; border-right-width: 0; border-top-width: 0; border-bottom-width: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; padding-left: 5px; padding-right: 5px; padding-top: 5px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px; margin-right: 5px; margin-left: 5px;" />
<ui:Button text="Load Sample Scene" display-tooltip-when-elided="true" name="LoadSampleSceneButton" style="-unity-text-align: middle-center; white-space: nowrap; flex-direction: row-reverse; align-items: auto; justify-content: flex-start; border-left-width: 0; border-right-width: 0; border-top-width: 0; border-bottom-width: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; padding-left: 5px; padding-right: 5px; padding-top: 5px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px; margin-right: 5px; margin-left: 5px;" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="OptimizeThePerformance" class="box" style="flex-shrink: 0; -unity-background-scale-mode: stretch-to-fill; margin-left: 7.5px; margin-right: 15px; margin-top: 0; margin-bottom: 15px; flex-direction: column; align-items: flex-start; justify-content: space-around; width: 227.5px; height: 135px;">
<ui:Label text="Optimize the performance" display-tooltip-when-elided="true" name="Heading" class="headingText" style="margin-left: 5px; margin-bottom: 10px; margin-top: 10px; margin-right: 5px; font-size: 14px;" />
<ui:Label text="Learn how Avatar Configurations can help you reach your performance goals." display-tooltip-when-elided="true" name="Description" style="white-space: normal; margin-left: 5px; margin-right: 5px;" />
<ui:Button text="See Docs" display-tooltip-when-elided="true" style="-unity-text-align: middle-center; white-space: nowrap; flex-direction: row-reverse; align-items: auto; justify-content: flex-start; border-left-width: 0; border-right-width: 0; border-top-width: 0; border-bottom-width: 0; border-top-left-radius: 0; border-bottom-left-radius: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; padding-left: 5px; padding-right: 5px; padding-top: 5px; padding-bottom: 5px; margin-top: 5px; margin-bottom: 5px; margin-right: 5px; margin-left: 5px;" />
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>
@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: 4a4f82d8946b5f74b88cd2a924583d70
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/IntegrationGuide/IntegrationGuide.uxml
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ed01ef66027d9e44cb56ecd86abf507b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,171 @@
using System.IO;
using ReadyPlayerMe.Core.Analytics;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace ReadyPlayerMe.Core.Editor
{
public class SettingsEditor : EditorWindow
{
private const string SETTINGS = "Settings";
private const string HEADER_LABEL = "HeaderLabel";
private const string CACHING_TOOLTIP =
"Enable caching to improve avatar loading performance at runtime.";
private const string AVATAR_CACHING_HEADING = "AvatarCachingHeading";
private const string AVATAR_CACHING_HELP_BUTTON = "AvatarCachingHelpButton";
private const string AVATAR_CACHING_ENABLED_TOGGLE = "AvatarCachingEnabledToggle";
private const string CLEAR_CACHE_BUTTON = "ClearCacheButton";
private const string SHOW_CACHE_BUTTON = "ShowCacheButton";
private const string ANALYTICS_ENABLED_TOGGLE = "AnalyticsEnabledToggle";
private const string LOGGING_ENABLED_TOGGLE = "LoggingEnabledToggle";
private const string DOCUMENTATION_BUTTON = "DocumentationButton";
private const string FAQ_BUTTON = "FaqButton";
private const string FORUM_BUTTON = "ForumButton";
private const string CLEAR_CACHE = "Clear Cache";
private const string CACHE_IS_ALREADY_EMPTY = "Cache is already empty";
private const string OK = "OK";
private const string CANCEL = "Cancel";
#if UNITY_EDITOR_LINUX
private const string SHOW_CACHING_FOLDER_BUTTON_TEXT = "Show in file manager";
#elif UNITY_EDITOR_OSX
private const string SHOW_CACHING_FOLDER_BUTTON_TEXT = "Reveal in finder";
#else
private const string SHOW_CACHING_FOLDER_BUTTON_TEXT = "Show in explorer";
#endif
private const string ANALYTICS_PRIVACY_URL = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/help-us-improve-the-unity-sdk";
private const string DOCS_URL = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity";
private const string FAQ_URL = "https://docs.readyplayer.me/ready-player-me/integration-guides/unity/faq-for-unity";
private const string FORUM_URL = "https://forum.readyplayer.me/";
private const string PRIVACY_POLICY_LABEL = "PrivacyPolicyLabel";
[SerializeField] private VisualTreeAsset visualTreeAsset;
private bool isCacheEmpty;
private Button clearCacheButton;
[MenuItem("Tools/Ready Player Me/Settings", priority = 1)]
public static void ShowWindow()
{
var window = GetWindow<SettingsEditor>();
window.titleContent = new GUIContent(SETTINGS);
window.minSize = new Vector2(500, 620);
AnalyticsEditorLogger.EventLogger.LogOpenDialog(SETTINGS);
}
public void CreateGUI()
{
visualTreeAsset.CloneTree(rootVisualElement);
var headerLabel = rootVisualElement.Q<Label>(HEADER_LABEL);
headerLabel.text = SETTINGS;
isCacheEmpty = AvatarCache.IsCacheEmpty();
rootVisualElement.Q(AVATAR_CACHING_HEADING).tooltip = CACHING_TOOLTIP;
rootVisualElement.Q<Button>(AVATAR_CACHING_HELP_BUTTON).clicked += OnCachingHelpClick;
var avatarCachingToggle = rootVisualElement.Q<Toggle>(AVATAR_CACHING_ENABLED_TOGGLE);
avatarCachingToggle.value = AvatarLoaderSettingsHelper.AvatarLoaderSettings.AvatarCachingEnabled;
avatarCachingToggle.RegisterValueChangedCallback(OnAvatarCachingToggle);
clearCacheButton = rootVisualElement.Q<Button>(CLEAR_CACHE_BUTTON);
clearCacheButton.clicked += TryClearCache;
clearCacheButton.SetEnabled(!isCacheEmpty);
var showCacheButton = rootVisualElement.Q<Button>(SHOW_CACHE_BUTTON);
showCacheButton.text = SHOW_CACHING_FOLDER_BUTTON_TEXT;
showCacheButton.clicked += ShowCacheDirectory;
var analyticsEnabledToggle = rootVisualElement.Q<Toggle>(ANALYTICS_ENABLED_TOGGLE);
analyticsEnabledToggle.value = AnalyticsEditorLogger.IsEnabled;
analyticsEnabledToggle.RegisterValueChangedCallback(OnAnalyticsToggled);
rootVisualElement.Q<Label>(PRIVACY_POLICY_LABEL).RegisterCallback<MouseUpEvent>(OnPrivacyPolicyClicked);
var loggingEnabledToggle = rootVisualElement.Q<Toggle>(LOGGING_ENABLED_TOGGLE);
loggingEnabledToggle.value = SDKLogger.IsLoggingEnabled();
loggingEnabledToggle.RegisterValueChangedCallback(OnLoggingToggle);
rootVisualElement.Q<Button>(DOCUMENTATION_BUTTON).clicked += () => Application.OpenURL(DOCS_URL);
rootVisualElement.Q<Button>(FAQ_BUTTON).clicked += () => Application.OpenURL(FAQ_URL);
rootVisualElement.Q<Button>(FORUM_BUTTON).clicked += () => Application.OpenURL(FORUM_URL);
}
private void OnCachingHelpClick()
{
AnalyticsEditorLogger.EventLogger.LogFindOutMore(HelpSubject.AvatarCaching);
Application.OpenURL(Constants.Links.DOCS_AVATAR_CACHING);
}
private void OnAvatarCachingToggle(ChangeEvent<bool> evt)
{
AvatarLoaderSettingsHelper.SetAvatarCaching(evt.newValue);
AnalyticsEditorLogger.EventLogger.LogSetCachingEnabled(evt.newValue);
}
private void OnLoggingToggle(ChangeEvent<bool> evt)
{
AnalyticsEditorLogger.EventLogger.LogSetLoggingEnabled(evt.newValue);
SDKLogger.EnableLogging(evt.newValue);
CoreSettingsSetter.SetEnableLogging(evt.newValue);
}
private void OnPrivacyPolicyClicked(MouseUpEvent evt)
{
AnalyticsEditorLogger.EventLogger.LogViewPrivacyPolicy();
Application.OpenURL(ANALYTICS_PRIVACY_URL);
}
private void OnFocus()
{
isCacheEmpty = AvatarCache.IsCacheEmpty();
clearCacheButton?.SetEnabled(!isCacheEmpty);
}
private void OnAnalyticsToggled(ChangeEvent<bool> evt)
{
if (evt.newValue)
{
AnalyticsEditorLogger.Enable();
}
else
{
AnalyticsEditorLogger.Disable();
}
}
private void TryClearCache()
{
AnalyticsEditorLogger.EventLogger.LogClearLocalCache();
if (isCacheEmpty)
{
EditorUtility.DisplayDialog(CLEAR_CACHE, CACHE_IS_ALREADY_EMPTY, OK);
return;
}
var size = (AvatarCache.GetCacheSize() / (1024f * 1024)).ToString("F2");
var avatarCount = AvatarCache.GetAvatarCount();
if (EditorUtility.DisplayDialog(CLEAR_CACHE, $"Do you want to clear all the Avatars cache from persistent data path, {size} MB and {avatarCount} avatars?", OK, CANCEL))
{
AvatarCache.Clear();
}
isCacheEmpty = true;
}
private void ShowCacheDirectory()
{
AnalyticsEditorLogger.EventLogger.LogShowInExplorer();
var path = DirectoryUtility.GetAvatarsPersistantPath();
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
EditorUtility.RevealInFinder(path);
}
}
}
@@ -0,0 +1,21 @@
fileFormatVersion: 2
guid: 5faa2baa58a589c4b8c7591b14e6846d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences:
- m_ViewDataDictionary: {instanceID: 0}
- visualTreeAsset: {fileID: 9197481963319205126, guid: c40a1d9fed7fb8e49afa8707ba507862,
type: 3}
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/SettingsWindow/SettingsEditor.cs
uploadId: 704624
@@ -0,0 +1,51 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<ui:Template name="HeaderTemplate" src="project://database/Assets/Ready%20Player%20Me/Core/Editor/Core/Scripts/UI/EditorWindows/Templates/HeaderTemplate.uxml?fileID=9197481963319205126&amp;guid=07a53a11b73eff34685f226bf17a42d4&amp;type=3#HeaderTemplate" />
<Style src="project://database/Assets/Ready%20Player%20Me/Core/Editor/Core/Scripts/UI/EditorWindows/CommonStyle.uss?fileID=7433441132597879392&amp;guid=af10d225241bded4188e82d92db9230f&amp;type=3#CommonStyle" />
<ui:VisualElement style="align-items: center; width: 500px; margin-left: auto; margin-right: auto; margin-top: 0; margin-bottom: auto;">
<ui:Instance template="HeaderTemplate" name="HeaderTemplate" />
<ui:VisualElement name="PartnerSettingsHeading" class="heading">
<ui:Label text="Application Settings" display-tooltip-when-elided="true" class="headingText" />
</ui:VisualElement>
<ReadyPlayerMe.Core.Editor.SubdomainTemplate style="flex-shrink: 0;" />
<ReadyPlayerMe.Core.Editor.AppIdTemplate style="flex-shrink: 0;" />
<ui:VisualElement name="AvatarSettings" style="flex-grow: 0; background-color: rgba(0, 0, 0, 0); height: auto; align-self: auto; justify-content: flex-start; align-items: stretch; flex-direction: flex-start; flex-shrink: 0;">
<ui:VisualElement name="AvatarSettingsHeading" class="heading">
<ui:Label text="Avatar Settings" display-tooltip-when-elided="true" class="headingText" />
</ui:VisualElement>
<ReadyPlayerMe.Core.Editor.AvatarConfigTemplate />
<ReadyPlayerMe.Core.Editor.AvatarBodyTypeTemplate />
<ReadyPlayerMe.Core.Editor.GltfDeferAgentTemplate />
</ui:VisualElement>
<ui:VisualElement name="AvatarCaching" style="flex-grow: 0; background-color: rgba(0, 0, 0, 0); flex-shrink: 0;">
<ui:VisualElement name="AvatarCachingHeading" class="heading">
<ui:Label text="Avatar Caching" display-tooltip-when-elided="true" class="headingText" />
<ui:Button text="?" display-tooltip-when-elided="true" name="AvatarCachingHelpButton" class="button2" style="margin-left: 0; margin-right: 0; margin-top: 0; margin-bottom: 0; padding-left: 0; padding-right: 0; padding-top: 0; padding-bottom: 0; width: 20px; height: 20px; border-top-left-radius: 15px; border-bottom-left-radius: 15px; border-top-right-radius: 15px; border-bottom-right-radius: 15px;" />
</ui:VisualElement>
<ui:Toggle label="Avatar caching enabled" name="AvatarCachingEnabledToggle" style="margin-left: 15px; margin-top: 10px; flex-direction: row-reverse; align-self: flex-start;" />
<ui:VisualElement name="Buttons" style="flex-grow: 0; background-color: rgba(0, 0, 0, 0); flex-direction: row; align-items: center; justify-content: flex-start; align-self: stretch; margin-left: 15px; margin-right: 15px; height: 40px; margin-top: 10px; width: 450px;">
<ui:Button text="Clear local avatar cache" display-tooltip-when-elided="true" name="ClearCacheButton" style="flex-grow: 0; white-space: nowrap; -unity-text-align: middle-center; text-overflow: ellipsis; -unity-font-style: bold; align-self: stretch; width: 230px; margin-left: 0; align-items: auto;" />
<ui:Button text="Show in Explorer" display-tooltip-when-elided="true" name="ShowCacheButton" style="flex-grow: 0; -unity-font-style: bold; align-self: stretch; align-items: auto; width: 230px;" />
</ui:VisualElement>
</ui:VisualElement>
<ui:VisualElement name="Other" style="flex-grow: 0; background-color: rgba(0, 0, 0, 0); flex-shrink: 0; align-items: flex-start; width: 500px;">
<ui:VisualElement name="OtherHeading" class="heading">
<ui:Label text="Other" display-tooltip-when-elided="true" class="headingText" />
</ui:VisualElement>
<ui:VisualElement name="AnalyticsEnabledContainer" style="flex-grow: 0; background-color: rgba(0, 0, 0, 0); flex-direction: row; justify-content: flex-start; align-self: flex-start; align-items: center; flex-shrink: 0;">
<ui:Toggle label="Analytics enabled" name="AnalyticsEnabledToggle" style="flex-direction: row-reverse; margin-left: 15px; margin-top: 5px; align-items: center;" />
<ui:Label tabindex="-1" text="(Privacy Policy)" display-tooltip-when-elided="true" name="PrivacyPolicyLabel" style="-unity-font-style: bold; margin-top: 3px; -unity-text-align: middle-left;" />
</ui:VisualElement>
<ui:Toggle label="Logging enabled" name="LoggingEnabledToggle" style="flex-direction: row-reverse; align-self: flex-start; margin-left: 15px; margin-top: 5px;" />
</ui:VisualElement>
<ui:VisualElement name="Support" style="flex-grow: 0; background-color: rgba(0, 0, 0, 0); flex-shrink: 0;">
<ui:VisualElement name="SupportHeading" class="heading">
<ui:Label text="Support" display-tooltip-when-elided="true" class="headingText" />
</ui:VisualElement>
<ui:VisualElement name="Buttons" style="flex-grow: 0; background-color: rgba(0, 0, 0, 0); flex-direction: row; align-self: auto; justify-content: space-between; align-items: center; height: 40px; margin-left: 15px; margin-right: 15px; margin-top: 10px; width: 450px; flex-shrink: 0;">
<ui:Button text="Documentation" display-tooltip-when-elided="true" name="DocumentationButton" style="width: 150px; align-items: auto; flex-grow: 0; justify-content: space-around; align-self: stretch; margin-left: 0; margin-right: 0;" />
<ui:Button text="FAQ" display-tooltip-when-elided="true" name="FaqButton" style="width: 150px; justify-content: space-around; align-self: stretch; align-items: auto; margin-left: 6px;" />
<ui:Button text="Forum" display-tooltip-when-elided="true" name="ForumButton" style="width: 150px; justify-content: space-around; align-self: stretch; align-items: auto; margin-right: 0;" />
</ui:VisualElement>
</ui:VisualElement>
</ui:VisualElement>
</ui:UXML>
@@ -0,0 +1,17 @@
fileFormatVersion: 2
guid: c40a1d9fed7fb8e49afa8707ba507862
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/SettingsWindow/SettingsEditorWindow.uxml
uploadId: 704624
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ad2bf8a8b88102a4dafffa09a848f549
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
using ReadyPlayerMe.Core.Analytics;
using UnityEditor;
namespace ReadyPlayerMe.Core.Editor
{
[InitializeOnLoad]
public static class OneTimeSetup
{
static OneTimeSetup()
{
if (!ProjectPrefs.GetBool(ProjectPrefs.FIRST_TIME_SETUP_DONE))
{
EditorApplication.update += OnStartup;
}
}
private static void OnStartup()
{
EditorApplication.update -= OnStartup;
AnalyticsEditorLogger.Enable();
SetupGuide.ShowWindow();
ProjectPrefs.SetBool(ProjectPrefs.FIRST_TIME_SETUP_DONE, true);
}
private static void OnQuit()
{
AnalyticsEditorLogger.EventLogger.LogCloseProject();
}
private static bool CanShowWindow()
{
return !ProjectPrefs.GetBool(ProjectPrefs.FIRST_TIME_SETUP_DONE);
}
}
}
@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: da47175f7f594aecb9f6e198bacdb941
timeCreated: 1686850921
AssetOrigin:
serializedVersion: 1
productId: 259814
packageName: Ready Player Me Avatar and Character Creator
packageVersion: 7.3.1
assetPath: Assets/Ready Player Me/Core/Editor/Core/Scripts/UI/EditorWindows/SetupGuide/OneTimeSetup.cs
uploadId: 704624

Some files were not shown because too many files have changed in this diff Show More