add ready player me POC
This commit is contained in:
@@ -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
|
||||
+19
@@ -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
|
||||
}
|
||||
+14
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -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);
|
||||
}
|
||||
}
|
||||
+18
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+18
@@ -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<string: name, string: version></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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -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
|
||||
+35
@@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -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
|
||||
+68
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -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:
|
||||
+44
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -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:
|
||||
+430
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -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
|
||||
+22
@@ -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>
|
||||
+17
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -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
|
||||
+46
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -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
|
||||
+73
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -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
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5bd53f8c2f141b74393738962a77da0f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+135
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -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
|
||||
+14
@@ -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>
|
||||
+17
@@ -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
|
||||
+56
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -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
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6e97a78112f684e40ad730948b73896b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+47
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -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
|
||||
+16
@@ -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('rpm_logo'); 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>
|
||||
+17
@@ -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:
|
||||
+127
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -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
|
||||
+39
@@ -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>
|
||||
+17
@@ -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:
|
||||
+171
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+21
@@ -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
|
||||
+51
@@ -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&guid=07a53a11b73eff34685f226bf17a42d4&type=3#HeaderTemplate" />
|
||||
<Style src="project://database/Assets/Ready%20Player%20Me/Core/Editor/Core/Scripts/UI/EditorWindows/CommonStyle.uss?fileID=7433441132597879392&guid=af10d225241bded4188e82d92db9230f&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>
|
||||
+17
@@ -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:
|
||||
+35
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -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
Reference in New Issue
Block a user