【m】插件上传

This commit is contained in:
2026-04-28 16:48:04 +08:00
parent 459db5ec01
commit 753878bdbb
631 changed files with 91583 additions and 11 deletions

View File

@@ -0,0 +1,4 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.RenderStreaming.RuntimeTests")]
[assembly: InternalsVisibleTo("Unity.RenderStreaming.EditorTests")]

View File

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

View File

@@ -0,0 +1,51 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomEditor(typeof(AudioStreamReceiver))]
[CanEditMultipleObjects]
internal class AudioStreamSenderReceiver : UnityEditor.Editor
{
class Styles
{
}
static Styles s_Styles;
SerializedProperty m_codec;
SerializedProperty m_targetAudioSource;
void OnEnable()
{
m_codec = serializedObject.FindProperty(AudioStreamReceiver.CodecPropertyName);
m_targetAudioSource = serializedObject.FindProperty(AudioStreamReceiver.TargetAudioSourcePropertyName);
}
void OnDisable()
{
}
public override void OnInspectorGUI()
{
if (s_Styles == null)
s_Styles = new Styles();
serializedObject.Update();
bool disableEditMediaSource = Application.isPlaying;
/// todo(kazuki): Make available to change video source parameters in runtime.
using (new EditorGUI.DisabledScope(disableEditMediaSource))
{
EditorGUILayout.PropertyField(m_targetAudioSource);
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_codec);
}
serializedObject.ApplyModifiedProperties();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,118 @@
#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomEditor(typeof(AudioStreamSender))]
[CanEditMultipleObjects]
internal class AudioStreamSenderEditor : UnityEditor.Editor
{
class Styles
{
public readonly GUIContent sourceContent =
EditorGUIUtility.TrTextContent("Audio Source Type", "Type of source the audio will be streamed.");
public readonly GUIContent bitrateContent =
EditorGUIUtility.TrTextContent("Bitrate (kbits/sec)", "A range of bitrate of audio streaming.");
}
static Styles s_Styles;
SerializedProperty m_source;
SerializedProperty m_codec;
SerializedProperty m_audioSource;
SerializedProperty m_audioListener;
SerializedProperty m_microphoneDeviceIndex;
SerializedProperty m_autoRequestUserAuthorization;
SerializedProperty m_loopback;
SerializedProperty m_bitrate;
static AnimBool[] m_sourceFade;
void OnEnable()
{
m_source = serializedObject.FindProperty(AudioStreamSender.SourcePropertyName);
m_audioSource = serializedObject.FindProperty(AudioStreamSender.AudioSourcePropertyName);
m_audioListener = serializedObject.FindProperty(AudioStreamSender.AudioListenerPropertyName);
m_microphoneDeviceIndex = serializedObject.FindProperty(AudioStreamSender.MicrophoneDeviceIndexPropertyName);
m_autoRequestUserAuthorization = serializedObject.FindProperty(AudioStreamSender.AutoRequestUserAuthorizationPropertyName);
m_codec = serializedObject.FindProperty(AudioStreamSender.CodecPropertyName);
m_bitrate = serializedObject.FindProperty(AudioStreamSender.BitratePropertyName);
m_loopback = serializedObject.FindProperty(AudioStreamSender.LoopbackPropertyName);
if (m_sourceFade == null)
{
m_sourceFade = new AnimBool[Enum.GetValues(typeof(AudioStreamSource)).Length];
for (int i = 0; i < m_sourceFade.Length; i++)
m_sourceFade[i] = new AnimBool(i == m_source.intValue);
}
Array.ForEach(m_sourceFade, anim => anim.valueChanged.AddListener(Repaint));
}
void OnDisable()
{
Array.ForEach(m_sourceFade, anim => anim.valueChanged.RemoveListener(Repaint));
}
public override void OnInspectorGUI()
{
if (s_Styles == null)
s_Styles = new Styles();
serializedObject.Update();
bool disableEditMediaSource = Application.isPlaying;
/// todo(kazuki): Make available to change video source parameters in runtime.
using (new EditorGUI.DisabledScope(disableEditMediaSource))
{
EditorGUILayout.PropertyField(m_source, s_Styles.sourceContent);
HandleSourceField();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_codec);
}
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_loopback);
if (target is AudioStreamSender sender && sender.isPlaying)
{
sender.loopback = m_loopback.boolValue;
}
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_bitrate, s_Styles.bitrateContent);
serializedObject.ApplyModifiedProperties();
}
private void HandleSourceField()
{
for (var i = 0; i < m_sourceFade.Length; i++)
m_sourceFade[i].target = m_source.intValue == i;
if (EditorGUILayout.BeginFadeGroup(m_sourceFade[(int)AudioStreamSource.AudioListener].faded))
{
EditorGUILayout.PropertyField(m_audioListener);
}
EditorGUILayout.EndFadeGroup();
if (EditorGUILayout.BeginFadeGroup(m_sourceFade[(int)AudioStreamSource.AudioSource].faded))
{
EditorGUILayout.PropertyField(m_audioSource);
}
EditorGUILayout.EndFadeGroup();
if (EditorGUILayout.BeginFadeGroup(m_sourceFade[(int)AudioStreamSource.Microphone].faded))
{
EditorGUILayout.PropertyField(m_microphoneDeviceIndex);
EditorGUILayout.PropertyField(m_autoRequestUserAuthorization);
}
EditorGUILayout.EndFadeGroup();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,111 @@
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.RenderStreaming.Editor
{
internal class ConfigInfoLine : VisualElement
{
static class Style
{
const string k_IconFolder = "Packages/com.unity.renderstreaming/Editor/Icon/";
public static readonly Texture ok = EditorGUIUtility.Load(k_IconFolder + "OK.png") as Texture;
public static readonly Texture error = EditorGUIUtility.Load(k_IconFolder + "Error.png") as Texture;
}
private readonly bool m_visibleStatus;
private readonly bool m_skipErrorIcon;
private Func<bool> m_tester;
private Func<bool> m_dependTester;
private bool m_haveFixer;
private bool m_currentStatus;
private bool m_dependStatus;
public ConfigInfoLine(
string label,
string error,
MessageType messageType,
string resolverButtonLabel,
Func<bool> tester,
Action resolver,
Func<bool> dependTester = null,
bool visibleStatus = true,
bool skipErrorIcon = false
)
{
m_visibleStatus = visibleStatus;
m_skipErrorIcon = skipErrorIcon;
m_tester = tester;
m_haveFixer = resolver != null;
m_dependTester = dependTester;
var testLabel = new Label(label) { name = "testLabel" };
var fixer = new Button(resolver) { text = resolverButtonLabel, name = "resolver" };
var testRow = new VisualElement() { name = "testRow" };
testRow.Add(testLabel);
if (m_visibleStatus)
{
var statusOk = new Image { image = Style.ok, name = "statusOK" };
var statusError = new Image { image = Style.error, name = "statusError" };
testRow.Add(statusOk);
testRow.Add(statusError);
}
testRow.Add(fixer);
Add(testRow);
HelpBoxMessageType kind;
switch (messageType)
{
default:
case MessageType.None:
kind = HelpBoxMessageType.None;
break;
case MessageType.Error:
kind = HelpBoxMessageType.Error;
break;
case MessageType.Warning:
kind = HelpBoxMessageType.Warning;
break;
case MessageType.Info:
kind = HelpBoxMessageType.Info;
break;
}
Add(new HelpBox(error, kind));
UpdateDisplay(m_currentStatus, m_haveFixer, m_dependStatus);
}
public void CheckUpdate()
{
bool wellConfigured = m_tester();
bool wellDependConfigured = m_dependTester == null || m_dependTester();
bool changeConfigured = wellConfigured ^ m_currentStatus;
bool changeDependConfigured = wellDependConfigured ^ m_dependStatus;
if (changeConfigured || changeDependConfigured)
{
UpdateDisplay(wellConfigured, m_haveFixer, wellDependConfigured);
m_currentStatus = wellConfigured;
m_dependStatus = wellDependConfigured;
}
}
private void UpdateDisplay(bool statusOK, bool haveFixer, bool dependStatusOK)
{
if (m_visibleStatus)
{
this.Q(name: "statusOK").style.display = statusOK ? DisplayStyle.Flex : DisplayStyle.None;
this.Q(name: "statusError").style.display = !statusOK
? (m_skipErrorIcon ? DisplayStyle.None : DisplayStyle.Flex)
: DisplayStyle.None;
}
var resolver = this.Q<Button>(name: "resolver");
resolver.style.display = statusOK || !haveFixer ? DisplayStyle.None : DisplayStyle.Flex;
resolver.SetEnabled(dependStatusOK);
this.Q(className: HelpBox.ussClassName).style.display = statusOK ? DisplayStyle.None : DisplayStyle.Flex;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 75e195dbcbb746ff83e761bef32d1871
timeCreated: 1673939682

View File

@@ -0,0 +1,98 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
/// <summary>
///
/// </summary>
public class CustomSignalingSettingsEditor : Attribute
{
private static readonly TypeCache.TypeCollection inspectorTypes =
TypeCache.GetTypesWithAttribute<CustomSignalingSettingsEditor>();
private readonly Type inspectedType;
private readonly string label;
/// <summary>
///
/// </summary>
/// <param name="inspectedType"></param>
/// <param name="label"></param>
public CustomSignalingSettingsEditor(Type inspectedType, string label)
{
if (inspectedType == null)
RenderStreaming.Logger.Log(LogType.Error, "Failed to load CustomEditor inspected type");
this.inspectedType = inspectedType;
this.label = label;
}
internal static Type FindInspectorTypeByInspectedType(Type inspectedType)
{
foreach (var type in inspectorTypes)
{
foreach (CustomSignalingSettingsEditor custom in
type.GetCustomAttributes(typeof(CustomSignalingSettingsEditor), false))
{
if (custom.inspectedType == inspectedType)
{
return type;
}
}
}
return null;
}
internal static Type FindInspectedTypeByLabel(string label)
{
foreach (var type in inspectorTypes)
{
foreach (CustomSignalingSettingsEditor custom in
type.GetCustomAttributes(typeof(CustomSignalingSettingsEditor), false))
{
if (custom.label == label)
{
return custom.inspectedType;
}
}
}
return null;
}
internal static string FindLabelByInspectedType(Type inspectedType)
{
foreach (var type in inspectorTypes)
{
foreach (CustomSignalingSettingsEditor custom in
type.GetCustomAttributes(typeof(CustomSignalingSettingsEditor), false))
{
if (custom.inspectedType == inspectedType)
{
return custom.label;
}
}
}
return null;
}
internal static string FindLabelByInspectorType(Type inspectorType)
{
var attributes =
inspectorType.GetCustomAttributes(typeof(CustomSignalingSettingsEditor), false);
foreach (var attribute in attributes)
{
if (attribute is CustomSignalingSettingsEditor custom)
return custom.label;
}
return null;
}
internal static IEnumerable<string> Labels()
{
return inspectorTypes.Select(FindLabelByInspectorType);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7750002ca172433e8ac04d3d8e3bb251
timeCreated: 1674544311

View File

@@ -0,0 +1,13 @@
using UnityEditor.PackageManager; //StatusCode
namespace Unity.RenderStreaming.Editor
{
internal interface IRequestJob
{
StatusCode Update();
}
} //namespace Unity.RenderStreaming.Editor

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 B

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

View File

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

View File

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

View File

@@ -0,0 +1,261 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Users;
using UnityEngine.InputSystem.Utilities;
namespace Unity.RenderStreaming.InputSystem.Editor
{
[CustomEditor(typeof(InputReceiver))]
internal class InputReceiverEditor : UnityEditor.Editor
{
public void OnEnable()
{
InputUser.onChange += OnUserChange;
m_Local = serializedObject.FindProperty(DataChannelBase.LocalPropertyName);
m_Label = serializedObject.FindProperty(DataChannelBase.LabelPropertyName);
m_Actions = serializedObject.FindProperty(InputReceiver.ActionsPropertyName);
m_ActionEvents = serializedObject.FindProperty(InputReceiver.ActionEventsPropertyName);
m_DefaultActionMap = serializedObject.FindProperty(InputReceiver.DefaultActionMapPropertyName);
}
private void OnUserChange(InputUser user, InputUserChange change, InputDevice device)
{
Repaint();
}
public override void OnInspectorGUI()
{
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_Local);
EditorGUILayout.PropertyField(m_Label);
// Action config section.
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(m_Actions);
if (EditorGUI.EndChangeCheck() || !m_ActionAssetInitialized)
OnActionAssetChange();
++EditorGUI.indentLevel;
if (m_ActionMapOptions != null && m_ActionMapOptions.Length > 0)
{
// Default action map picker.
var selected = EditorGUILayout.Popup(m_DefaultActionMapText, m_SelectedDefaultActionMap,
m_ActionMapOptions);
if (selected != m_SelectedDefaultActionMap)
{
if (selected == 0)
{
m_DefaultActionMap.stringValue = null;
}
else
{
// Use ID rather than name.
var asset = (InputActionAsset)m_Actions.objectReferenceValue;
var actionMap = asset.FindActionMap(m_ActionMapOptions[selected].text);
if (actionMap != null)
m_DefaultActionMap.stringValue = actionMap.id.ToString();
}
m_SelectedDefaultActionMap = selected;
}
}
--EditorGUI.indentLevel;
// Notifications/event section.
m_EventsGroupUnfolded = EditorGUILayout.Foldout(m_EventsGroupUnfolded, m_EventsGroupText, toggleOnLabelClick: true);
if (m_EventsGroupUnfolded)
{
// Action events. Group by action map.
if (m_ActionNames != null)
{
using (new EditorGUI.IndentLevelScope())
{
for (var n = 0; n < m_NumActionMaps; ++n)
{
m_ActionMapEventsUnfolded[n] = EditorGUILayout.Foldout(m_ActionMapEventsUnfolded[n],
m_ActionMapNames[n], toggleOnLabelClick: true);
using (new EditorGUI.IndentLevelScope())
{
if (m_ActionMapEventsUnfolded[n])
{
for (var i = 0; i < m_ActionNames.Length; ++i)
{
if (m_ActionMapIndices[i] != n)
continue;
EditorGUILayout.PropertyField(m_ActionEvents.GetArrayElementAtIndex(i), m_ActionNames[i]);
}
}
}
}
}
}
}
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
// Debug UI.
if (EditorApplication.isPlaying)
DoDebugUI();
}
private void DoDebugUI()
{
var playerInput = (InputReceiver)target;
if (!playerInput.user.valid)
return;
////TODO: show actions when they happen
var user = playerInput.user.index.ToString();
//var controlScheme = playerInput.user.controlScheme?.name;
var devices = playerInput.user.pairedDevices.Select(_ => _.ToString()).OrderBy(x => x).ToArray();
EditorGUILayout.Space();
EditorGUILayout.LabelField(m_DebugText, EditorStyles.boldLabel);
++EditorGUI.indentLevel;
EditorGUILayout.LabelField("User", $"#{user}");
//EditorGUILayout.LabelField("Control Scheme", controlScheme);
m_DevicesGroupUnfolded = EditorGUILayout.Foldout(
m_DevicesGroupUnfolded, m_DevicesGroupText, toggleOnLabelClick: true);
if (m_DevicesGroupUnfolded)
{
using (new EditorGUI.IndentLevelScope())
{
foreach (var device in devices)
{
EditorGUILayout.LabelField(device.ToString());
// todo: InputDeviceDebuggerWindow is an internal class
// InputDeviceDebuggerWindow.CreateOrShowExisting(device);
}
}
}
--EditorGUI.indentLevel;
}
private void OnActionAssetChange()
{
serializedObject.ApplyModifiedProperties();
m_ActionAssetInitialized = true;
var playerInput = (InputReceiver)target;
var asset = (InputActionAsset)m_Actions.objectReferenceValue;
if (asset == null)
{
m_ActionMapOptions = null;
return;
}
var newActionNames = new List<GUIContent>();
var newActionEvents = new List<PlayerInput.ActionEvent>();
var newActionMapIndices = new List<int>();
void AddEntry(InputAction action, PlayerInput.ActionEvent actionEvent)
{
newActionNames.Add(new GUIContent(action.name));
newActionEvents.Add(actionEvent);
var actionMapIndex = asset.actionMaps.IndexOfReference(action.actionMap);
newActionMapIndices.Add(actionMapIndex);
if (actionMapIndex >= m_NumActionMaps)
m_NumActionMaps = actionMapIndex + 1;
ArrayHelpers.PutAtIfNotSet(ref m_ActionMapNames, actionMapIndex,
() => new GUIContent(action.actionMap.name));
}
// Bring over any action events that we already have and that are still in the asset.
var oldActionEvents = playerInput.m_ActionEvents;
if (oldActionEvents != null)
{
foreach (var entry in oldActionEvents)
{
var guid = entry.actionId;
var action = asset.FindAction(guid);
if (action != null)
AddEntry(action, entry);
}
}
// Add any new actions.
foreach (var action in asset)
{
// Skip if it was already in there.
if (oldActionEvents != null && oldActionEvents.Any(x => x.actionId == action.id.ToString()))
continue;
////FIXME: adds bindings to the name
AddEntry(action, new PlayerInput.ActionEvent(action.id, action.ToString()));
}
m_ActionNames = newActionNames.ToArray();
m_ActionMapIndices = newActionMapIndices.ToArray();
Array.Resize(ref m_ActionMapEventsUnfolded, m_NumActionMaps);
playerInput.m_ActionEvents = newActionEvents.ToArray();
// Read out action maps.
var selectedDefaultActionMap = !string.IsNullOrEmpty(playerInput.defaultActionMap)
? asset.FindActionMap(playerInput.defaultActionMap)
: null;
m_SelectedDefaultActionMap = asset.actionMaps.Count > 0 ? 1 : 0;
var actionMaps = asset.actionMaps;
m_ActionMapOptions = new GUIContent[actionMaps.Count + 1];
m_ActionMapOptions[0] = new GUIContent(EditorGUIUtility.TrTextContent("<None>"));
////TODO: sort alphabetically
for (var i = 0; i < actionMaps.Count; ++i)
{
var actionMap = actionMaps[i];
m_ActionMapOptions[i + 1] = new GUIContent(actionMap.name);
if (selectedDefaultActionMap != null && actionMap == selectedDefaultActionMap)
m_SelectedDefaultActionMap = i + 1;
}
if (m_SelectedDefaultActionMap <= 0)
playerInput.defaultActionMap = null;
else
playerInput.defaultActionMap = m_ActionMapOptions[m_SelectedDefaultActionMap].text;
serializedObject.Update();
}
[SerializeField] private bool m_EventsGroupUnfolded;
[SerializeField] private bool m_DevicesGroupUnfolded;
[SerializeField] private bool[] m_ActionMapEventsUnfolded;
[NonSerialized]
private readonly GUIContent m_EventsGroupText =
EditorGUIUtility.TrTextContent("Events", "UnityEvents triggered by the PlayerInput component");
[NonSerialized]
private readonly GUIContent m_DefaultActionMapText =
EditorGUIUtility.TrTextContent("Default Map", "Action map to enable by default. If not set, no actions will be enabled by default.");
[NonSerialized]
private readonly GUIContent m_DebugText = EditorGUIUtility.TrTextContent("Debug");
[NonSerialized]
private readonly GUIContent m_DevicesGroupText =
EditorGUIUtility.TrTextContent("Paired Devices", "InputDevices paired by the PlayerInput component");
[NonSerialized] private GUIContent[] m_ActionNames;
[NonSerialized] private GUIContent[] m_ActionMapNames;
[NonSerialized] private int[] m_ActionMapIndices;
[NonSerialized] private int m_NumActionMaps;
[NonSerialized] private SerializedProperty m_ActionEvents;
[NonSerialized] private int m_SelectedDefaultActionMap;
[NonSerialized] private GUIContent[] m_ActionMapOptions;
[NonSerialized] private SerializedProperty m_Local;
[NonSerialized] private SerializedProperty m_Label;
[NonSerialized] private SerializedProperty m_Actions;
[NonSerialized] private SerializedProperty m_DefaultActionMap;
[NonSerialized] private bool m_ActionAssetInitialized;
}
}

View File

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

View File

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

View File

@@ -0,0 +1,112 @@
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomPropertyDrawer(typeof(BitrateAttribute))]
class BitrateDrawer : PropertyDrawer
{
SerializedProperty propertyMinimum;
SerializedProperty propertyMaximum;
bool cache = false;
bool changed = false;
int minLimit;
int maxLimit;
static readonly GUIContent s_bitrateLabel =
EditorGUIUtility.TrTextContent("Bitrate (kbits/sec)", "A range of bitrate of streaming.");
static readonly GUIContent s_minBitrateLabel =
EditorGUIUtility.TrTextContent("Min");
static readonly GUIContent s_maxBitrateLabel =
EditorGUIUtility.TrTextContent("Max");
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (!cache)
{
propertyMinimum = property.FindPropertyInChildren("min");
propertyMaximum = property.FindPropertyInChildren("max");
var attr = attribute as BitrateAttribute;
minLimit = attr.minValue;
maxLimit = attr.maxValue;
property.Reset();
cache = true;
}
var rect = position;
rect.height = EditorGUIUtility.singleLineHeight;
EditorGUI.BeginProperty(rect, label, property);
float minValue = propertyMinimum.intValue;
float maxValue = propertyMaximum.intValue;
// slider
EditorGUI.BeginChangeCheck();
rect = EditorGUI.PrefixLabel(rect, s_bitrateLabel);
EditorGUI.MinMaxSlider(rect, ref minValue, ref maxValue, minLimit, maxLimit);
int min = (int)minValue;
int max = (int)maxValue;
if (EditorGUI.EndChangeCheck())
{
propertyMinimum.intValue = min;
propertyMaximum.intValue = max;
changed = true;
}
EditorGUI.EndProperty();
// min value
EditorGUI.BeginChangeCheck();
rect.y += EditorGUIUtility.singleLineHeight;
min = EditorGUI.IntField(rect, s_minBitrateLabel, min);
if (EditorGUI.EndChangeCheck())
{
min = Mathf.Max(min, minLimit);
min = Mathf.Min(min, max);
propertyMinimum.intValue = min;
changed = true;
}
// max value
EditorGUI.BeginChangeCheck();
rect.y += EditorGUIUtility.singleLineHeight;
max = EditorGUI.IntField(rect, s_maxBitrateLabel, max);
if (EditorGUI.EndChangeCheck())
{
max = Mathf.Min(max, maxLimit);
max = Mathf.Max(min, max);
propertyMaximum.intValue = max;
changed = true;
}
if (changed)
{
if (Application.isPlaying)
{
var objectReferenceValue = property.serializedObject.targetObject;
var type = objectReferenceValue.GetType();
var attribute = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var methodName = "SetBitrate";
var method = type.GetMethod(methodName, attribute);
method.Invoke(objectReferenceValue, new object[] { (uint)min, (uint)max });
}
changed = false;
}
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
//var height = 0f;
return EditorGUIUtility.singleLineHeight * 3;
//return height;
}
}
}

View File

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

View File

@@ -0,0 +1,284 @@
#if UNITY_EDITOR
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomPropertyDrawer(typeof(CodecAttribute))]
class CodecDrawer : PropertyDrawer
{
interface Codec
{
string name { get; }
string mimeType { get; }
string sdpFmtpLine { get; }
int channelCount { get; }
int sampleRate { get; }
string optionTitle { get; }
int order { get; }
}
class AudioCodec : Codec
{
public string name { get { return codec_.name; } }
public string mimeType { get { return codec_.mimeType; } }
public string sdpFmtpLine { get { return codec_.sdpFmtpLine; } }
public int channelCount { get { return codec_.channelCount; } }
public int sampleRate { get { return codec_.sampleRate; } }
public string optionTitle
{
get
{
return $"{codec_.channelCount} channel";
}
}
public int order { get { return codec_.channelCount; } }
public AudioCodec(AudioCodecInfo codec)
{
codec_ = codec;
}
AudioCodecInfo codec_;
}
class VideoCodec : Codec
{
public string name { get { return codec_.name; } }
public string mimeType { get { return codec_.mimeType; } }
public string sdpFmtpLine { get { return codec_.sdpFmtpLine; } }
public string optionTitle
{
get
{
switch (codec_)
{
case H264CodecInfo h264Codec:
return $"{h264Codec.profile} Profile, Level {h264Codec.level.ToString().Insert(1, ".")}";
case VP9CodecInfo vp9codec:
return $"Profile {(int)vp9codec.profile}";
case AV1CodecInfo av1codec:
return $"Profile {(int)av1codec.profile}";
}
return null;
}
}
public int channelCount { get { throw new NotSupportedException(); } }
public int sampleRate { get { throw new NotSupportedException(); } }
public int order
{
get
{
switch (codec_)
{
case H264CodecInfo h264Codec:
return (int)h264Codec.profile;
case VP9CodecInfo vp9codec:
return (int)vp9codec.profile;
case AV1CodecInfo av1codec:
return (int)av1codec.profile;
}
return 0;
}
}
public VideoCodec(VideoCodecInfo codec)
{
codec_ = codec;
}
VideoCodecInfo codec_;
}
SerializedProperty propertyMimeType;
SerializedProperty propertySdpFmtpLine;
SerializedProperty propertyChannelCount;
SerializedProperty propertySampleRate;
IEnumerable<Codec> codecs;
string[] codecNames = new string[] { "Default" };
string[] codecOptions = new string[] { };
IEnumerable<Codec> selectedCodecs;
GUIContent codecLabel;
int selectCodecIndex = 0;
int selectCodecOptionIndex = 0;
bool hasCodecOptions = false;
bool cache = false;
bool changed = false;
static readonly GUIContent s_audioCodecLabel =
EditorGUIUtility.TrTextContent("Audio Codec", "Audio encoding codec.");
static readonly GUIContent s_videoCodecLabel =
EditorGUIUtility.TrTextContent("Video Codec", "Video encoding codec.");
static IEnumerable<Codec> GetAvailableCodecs(UnityEngine.Object target)
{
if (target is VideoStreamSender)
{
return VideoStreamSender.GetAvailableCodecs().Select(codec => new VideoCodec(codec));
}
else if (target is VideoStreamReceiver)
{
return VideoStreamReceiver.GetAvailableCodecs().Select(codec => new VideoCodec(codec));
}
else if (target is AudioStreamSender)
{
return AudioStreamSender.GetAvailableCodecs().Select(codec => new AudioCodec(codec));
}
else if (target is AudioStreamReceiver)
{
return AudioStreamReceiver.GetAvailableCodecs().Select(codec => new AudioCodec(codec));
}
throw new ArgumentException();
}
static GUIContent GetCodecLabel(UnityEngine.Object target)
{
if (target is VideoStreamSender || target is VideoStreamReceiver)
{
return s_videoCodecLabel;
}
else if (target is AudioStreamSender || target is AudioStreamReceiver)
{
return s_audioCodecLabel;
}
throw new ArgumentException();
}
int FindOptionIndex(IEnumerable<Codec> codecs)
{
return Array.FindIndex(codecs.ToArray(), codec =>
{
if (codec is VideoCodec)
return codec.sdpFmtpLine == propertySdpFmtpLine.stringValue;
else
return
codec.sdpFmtpLine == propertySdpFmtpLine.stringValue &&
codec.channelCount == propertyChannelCount.intValue &&
codec.sampleRate == propertySampleRate.intValue;
});
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (!cache)
{
propertyMimeType = property.FindPropertyInChildren("m_MimeType");
propertySdpFmtpLine = property.FindPropertyInChildren("m_SdpFmtpLine");
propertyChannelCount = property.FindPropertyInChildren("m_ChannelCount");
propertySampleRate = property.FindPropertyInChildren("m_SampleRate");
codecs = GetAvailableCodecs(property.serializedObject.targetObject);
codecNames = codecNames.Concat(codecs.Select(codec => codec.name)).Distinct().ToArray();
var mimeType = propertyMimeType.stringValue;
var codecName = mimeType.GetCodecName();
selectedCodecs = codecs.Where(codec => codec.name == codecName).OrderBy(codec => codec.order);
codecOptions = selectedCodecs.Select(codec => codec.optionTitle).ToArray();
if (!selectedCodecs.Any())
selectCodecIndex = 0;
else
selectCodecIndex = Array.FindIndex(codecNames, codec => codec == codecName);
codecLabel = GetCodecLabel(property.serializedObject.targetObject);
hasCodecOptions = codecOptions.Length > 1;
if (hasCodecOptions)
selectCodecOptionIndex = FindOptionIndex(selectedCodecs);
cache = true;
}
var rect = position;
rect.height = EditorGUIUtility.singleLineHeight;
EditorGUI.BeginProperty(rect, label, propertyMimeType);
rect = EditorGUI.PrefixLabel(rect, codecLabel);
EditorGUI.BeginChangeCheck();
selectCodecIndex = EditorGUI.Popup(rect, selectCodecIndex, codecNames);
if (EditorGUI.EndChangeCheck())
{
if (0 < selectCodecIndex)
{
string codecName = codecNames[selectCodecIndex];
selectedCodecs = codecs.Where(codec => codec.name == codecName).OrderBy(codec => codec.order);
codecOptions = selectedCodecs.Select(codec => codec.optionTitle).ToArray();
hasCodecOptions = codecOptions.Length > 1;
var codec = selectedCodecs.First();
propertyMimeType.stringValue = codec.mimeType;
propertySdpFmtpLine.stringValue = codec.sdpFmtpLine;
if (propertyChannelCount != null)
propertyChannelCount.intValue = codec.channelCount;
if (propertySampleRate != null)
propertySampleRate.intValue = codec.sampleRate;
}
else
{
propertyMimeType.stringValue = null;
propertySdpFmtpLine.stringValue = null;
if (propertyChannelCount != null)
propertyChannelCount.intValue = 0;
if (propertySampleRate != null)
propertySampleRate.intValue = 0;
hasCodecOptions = false;
}
}
EditorGUI.EndProperty();
int codecIndex = selectCodecIndex - 1;
if (0 < codecIndex)
{
if (hasCodecOptions && 0 < codecOptions.Length)
{
// sdp fmtp line
rect.y += EditorGUIUtility.singleLineHeight;
EditorGUI.BeginProperty(rect, label, propertySdpFmtpLine);
EditorGUI.BeginChangeCheck();
selectCodecOptionIndex = EditorGUI.Popup(rect, selectCodecOptionIndex, codecOptions);
if (EditorGUI.EndChangeCheck())
{
var codec = selectedCodecs.ElementAt(selectCodecOptionIndex);
propertySdpFmtpLine.stringValue = codec.sdpFmtpLine;
if (propertyChannelCount != null)
propertyChannelCount.intValue = codec.channelCount;
if (propertySampleRate != null)
propertySampleRate.intValue = codec.sampleRate;
}
EditorGUI.EndProperty();
}
}
if (changed)
{
// todo: not supported changing codecs in play mode.
//if (Application.isPlaying)
//{
// var objectReferenceValue = property.serializedObject.targetObject;
// var type = objectReferenceValue.GetType();
// var attribute = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
// var methodName = "SetCodec";
// var method = type.GetMethod(methodName, attribute);
// method.Invoke(objectReferenceValue, new object[] { newValue });
//}
changed = false;
}
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (property == null)
throw new System.ArgumentNullException(nameof(property));
int lineCount = hasCodecOptions ? 2 : 1;
return EditorGUIUtility.singleLineHeight * lineCount;
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ffbb807e4a1ab4440a236d73776265b3
timeCreated: 1637904184

View File

@@ -0,0 +1,99 @@
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomPropertyDrawer(typeof(FrameRateAttribute))]
class FrameRateDrawer : PropertyDrawer
{
readonly GUIContent[] frameRateText =
{
EditorGUIUtility.TrTextContent("Default"),
EditorGUIUtility.TrTextContent("10"),
EditorGUIUtility.TrTextContent("15"),
EditorGUIUtility.TrTextContent("20"),
EditorGUIUtility.TrTextContent("30"),
EditorGUIUtility.TrTextContent("60"),
};
readonly float?[] frameRateValues =
{
null,
10,
15,
20,
30,
60
};
readonly GUIContent s_FramerateLabel =
EditorGUIUtility.TrTextContent("Framerate",
"Video encoding framerate.");
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
float value = property.floatValue;
var selectIndex = 1;
while (selectIndex < frameRateValues.Length && !Mathf.Approximately(value, frameRateValues[selectIndex].Value))
{
++selectIndex;
}
// default value
if (selectIndex == frameRateValues.Length)
selectIndex = 0;
var popupRect = position;
popupRect.height = EditorGUIUtility.singleLineHeight;
selectIndex = EditorGUI.Popup(popupRect, s_FramerateLabel,
selectIndex, frameRateText);
float newValue;
var cutomValueRect = position;
cutomValueRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
cutomValueRect.height = 0;
if (0 < selectIndex && selectIndex < frameRateValues.Length)
{
newValue = frameRateValues[selectIndex].Value;
}
else
{
newValue = 0;
}
if (!Mathf.Approximately(value, newValue))
{
if (Application.isPlaying)
{
var objectReferenceValue = property.serializedObject.targetObject;
var type = objectReferenceValue.GetType();
var attribute = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var methodName = "SetFrameRate";
var method = type.GetMethod(methodName, attribute);
method.Invoke(objectReferenceValue, new object[] { newValue });
}
else
{
property.floatValue = newValue;
}
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (property == null)
throw new System.ArgumentNullException(nameof(property));
var height = 0f;
// Popup.
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
return height;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6955fbf0f885c624786f638fdcca131a
timeCreated: 1637904184

View File

@@ -0,0 +1,27 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomPropertyDrawer(typeof(RenderTextureDepthBufferAttribute))]
public class RenderTextureDepthBufferDrawer : PropertyDrawer
{
readonly GUIContent[] renderTextureDepthBuffer = new GUIContent[3]
{
EditorGUIUtility.TrTextContent("No depth buffer"),
EditorGUIUtility.TrTextContent("At least 16 bits depth (no stencil)"),
EditorGUIUtility.TrTextContent("At least 24 bits depth (with stencil)")
};
readonly int[] renderTextureDepthBufferValues = new int[3] { 0, 16, 24 };
readonly GUIContent depthBuffer = EditorGUIUtility.TrTextContent("Depth Buffer", "Format of the depth buffer.");
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.IntPopup(position, property, renderTextureDepthBuffer, renderTextureDepthBufferValues, depthBuffer);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,30 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomPropertyDrawer(typeof(RenderTextureAntiAliasingAttribute))]
public class RenderTexureAntiAliasingDrawer : PropertyDrawer
{
readonly GUIContent[] renderTextureAntiAliasing = new GUIContent[4]
{
EditorGUIUtility.TrTextContent("None"),
EditorGUIUtility.TrTextContent("2 samples"),
EditorGUIUtility.TrTextContent("4 samples"),
EditorGUIUtility.TrTextContent("8 samples")
};
readonly int[] renderTextureAntiAliasingValues = new int[4] { 1, 2, 4, 8 };
readonly GUIContent antiAliasing =
EditorGUIUtility.TrTextContent("Anti-aliasing", "Number of anti-aliasing samples.");
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.IntPopup(position, property, renderTextureAntiAliasing, renderTextureAntiAliasingValues, antiAliasing);
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,89 @@
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomPropertyDrawer(typeof(ScaleResolutionAttribute))]
class ScaleResolutionDrawer : PropertyDrawer
{
readonly GUIContent[] scaleFactorText =
{
EditorGUIUtility.TrTextContent("No Scale"),
EditorGUIUtility.TrTextContent("1 \u2215 2"),
EditorGUIUtility.TrTextContent("1 \u2215 4"),
EditorGUIUtility.TrTextContent("1 \u2215 8"),
EditorGUIUtility.TrTextContent("1 \u2215 16"),
};
readonly float[] scaleFactorValues =
{
1,
2,
4,
8,
16,
};
readonly GUIContent s_ScaleResolutionLabel =
EditorGUIUtility.TrTextContent("Scale Resolution Down",
"Downscaling video resolution to reduce bandwidth.");
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
float value = property.floatValue;
var selectIndex = 1;
while (selectIndex < scaleFactorValues.Length && !Mathf.Approximately(value, scaleFactorValues[selectIndex]))
{
++selectIndex;
}
// default value
if (selectIndex == scaleFactorValues.Length)
selectIndex = 0;
var popupRect = position;
popupRect.height = EditorGUIUtility.singleLineHeight;
selectIndex = EditorGUI.Popup(popupRect, s_ScaleResolutionLabel,
selectIndex, scaleFactorText);
float newValue;
var cutomValueRect = position;
cutomValueRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
cutomValueRect.height = 0;
newValue = scaleFactorValues[selectIndex];
if (!Mathf.Approximately(value, newValue))
{
property.floatValue = newValue;
if (Application.isPlaying)
{
var objectReferenceValue = property.serializedObject.targetObject;
var type = objectReferenceValue.GetType();
var attribute = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var methodName = "SetScaleResolutionDown";
var method = type.GetMethod(methodName, attribute);
method.Invoke(objectReferenceValue, new object[] { newValue });
}
}
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (property == null)
throw new System.ArgumentNullException(nameof(property));
var height = 0f;
// Popup.
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
return height;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f81bb4eb3b702494db296db9976c321f
timeCreated: 1637904184

View File

@@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace Unity.RenderStreaming.Editor
{
[CustomPropertyDrawer(typeof(SignalingSettingsAttribute))]
class SignalingSettingsDrawer : PropertyDrawer
{
private VisualElement editorGUI;
private PopupField<string> popupFieldSignalingType;
private ISignalingSettingEditor editor;
private Dictionary<Type, SignalingSettings> table = new Dictionary<Type, SignalingSettings>();
public override VisualElement CreatePropertyGUI(SerializedProperty property)
{
editor = CreateEditor(property);
var root = new VisualElement();
root.RegisterCallback<SerializedPropertyChangeEvent, SerializedProperty>(OnSignalingSettingsObjectChange, property);
var box = new Box();
root.Add(box);
editorGUI = editor.CreateInspectorGUI(property);
popupFieldSignalingType = CreatePopUpSignalingType(property, "Signaling Type");
popupFieldSignalingType.RegisterValueChangedCallback(e => OnPopupFieldValueChange(e, property));
box.Add(popupFieldSignalingType);
box.Add(editorGUI);
return root;
}
ISignalingSettingEditor CreateEditor(SerializedProperty property)
{
var settings = fieldInfo.GetValue(property.serializedObject.targetObject) as SignalingSettings;
var type = CustomSignalingSettingsEditor.FindInspectorTypeByInspectedType(settings.GetType());
return Activator.CreateInstance(type) as ISignalingSettingEditor;
}
PopupField<string> CreatePopUpSignalingType(SerializedProperty property, string label)
{
var settings = fieldInfo.GetValue(property.serializedObject.targetObject) as SignalingSettings;
var defaultValue = CustomSignalingSettingsEditor.FindLabelByInspectedType(settings.GetType());
var choices = CustomSignalingSettingsEditor.Labels().ToList();
var field = new PopupField<string>(label: label, choices: choices, defaultValue: defaultValue);
field.tooltip = "Choose the signaling type. \"WebSocket\" or \"HTTP Polling\".";
return field;
}
static void ReplaceVisualElement(VisualElement oldValue, VisualElement newValue)
{
var root = oldValue.parent;
var index = root.IndexOf(oldValue);
root.Remove(oldValue);
root.Insert(index, newValue);
}
void OnSignalingSettingsObjectChange(SerializedPropertyChangeEvent e, SerializedProperty property)
{
var settings = fieldInfo.GetValue(property.serializedObject.targetObject) as SignalingSettings;
var label = CustomSignalingSettingsEditor.FindLabelByInspectedType(settings.GetType());
if (popupFieldSignalingType.value == label)
return;
popupFieldSignalingType.value = label;
RecreateEditorGUI(label, property);
}
void OnPopupFieldValueChange(ChangeEvent<string> e, SerializedProperty property)
{
if (!(fieldInfo.GetValue(property.serializedObject.targetObject) is SignalingSettings settings))
return;
// cache current settings.
var type = settings.GetType();
table[type] = settings;
var label = e.newValue;
RecreateEditorGUI(label, property);
}
void RecreateEditorGUI(string label, SerializedProperty property)
{
var inspectedType = CustomSignalingSettingsEditor.FindInspectedTypeByLabel(label);
if (!table.ContainsKey(inspectedType))
{
var newSettings = Activator.CreateInstance(inspectedType) as SignalingSettings;
table.Add(inspectedType, newSettings);
}
property.managedReferenceValue = table[inspectedType];
property.serializedObject.ApplyModifiedProperties();
var inspectorType = CustomSignalingSettingsEditor.FindInspectorTypeByInspectedType(inspectedType);
editor = Activator.CreateInstance(inspectorType) as ISignalingSettingEditor;
var newValue = editor.CreateInspectorGUI(property);
// Unbind old element to serializedObject.
editorGUI.Unbind();
ReplaceVisualElement(editorGUI, newValue);
editorGUI = newValue;
// bind new element to serializedObject.
editorGUI.Bind(property.serializedObject);
}
}
/// <summary>
///
/// </summary>
public interface ISignalingSettingEditor
{
VisualElement CreateInspectorGUI(SerializedProperty property);
}
[CustomSignalingSettingsEditor(typeof(HttpSignalingSettings), "HTTP Polling")]
internal class HttpSignalingSettingsEditor : ISignalingSettingEditor
{
public VisualElement CreateInspectorGUI(SerializedProperty property)
{
VisualElement root = new VisualElement();
root.Add(new PropertyField(property.FindPropertyRelative("m_url"), "URL"));
root.Add(new PropertyField(property.FindPropertyRelative("m_interval"), "Polling Interval (msec)"));
root.Add(new PropertyField(property.FindPropertyRelative("m_iceServers"), "ICE Servers"));
return root;
}
}
[CustomSignalingSettingsEditor(typeof(WebSocketSignalingSettings), "WebSocket")]
internal class WebSocketSignalingSettingsEditor : ISignalingSettingEditor
{
public VisualElement CreateInspectorGUI(SerializedProperty property)
{
VisualElement root = new VisualElement();
root.Add(new PropertyField(property.FindPropertyRelative("m_url"), "URL"));
root.Add(new PropertyField(property.FindPropertyRelative("m_iceServers"), "ICE Servers"));
return root;
}
}
}

View File

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

View File

@@ -0,0 +1,130 @@
using System.Reflection;
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomPropertyDrawer(typeof(StreamingSizeAttribute))]
class StreamingSizeDrawer : PropertyDrawer
{
readonly GUIContent[] streamingSizeText =
{
EditorGUIUtility.TrTextContent("640 x 480"),
EditorGUIUtility.TrTextContent("1280 x 720"),
EditorGUIUtility.TrTextContent("1600 x 1200"),
EditorGUIUtility.TrTextContent("1920 x 1200"),
EditorGUIUtility.TrTextContent("2560 x 1440"),
EditorGUIUtility.TrTextContent("Custom")
};
readonly Vector2Int[] streamingSizeValues =
{
new Vector2Int(640, 480),
new Vector2Int(1280, 720), new Vector2Int(1600, 1200),
new Vector2Int(1920, 1200), new Vector2Int(2560, 1440),
};
readonly GUIContent s_StreamingSizeLabel =
EditorGUIUtility.TrTextContent("Streaming Size",
"Streaming size should match display aspect ratio.");
readonly GUIContent s_customValueLabel =
EditorGUIUtility.TrTextContent("Custom Value",
"Supporting resolutions are difference each platforms.");
private static readonly string s_HelpBoxText =
"Note that streaming might not operate properly " +
"when set some resolutions. " +
"Platforms or type of encoders are depended.";
private bool IsCustomValue(Vector2Int value)
{
return !ArrayUtility.Contains(streamingSizeValues, value);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty(position, label, property);
Vector2Int value = property.vector2IntValue;
var selectIndex = 0;
while (selectIndex < streamingSizeValues.Length &&
value != streamingSizeValues[selectIndex])
{
++selectIndex;
}
var popupRect = position;
popupRect.height = EditorGUIUtility.singleLineHeight;
selectIndex = EditorGUI.Popup(popupRect, s_StreamingSizeLabel,
selectIndex, streamingSizeText);
Vector2Int newValue;
var cutomValueRect = position;
cutomValueRect.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
if (selectIndex < streamingSizeValues.Length)
{
newValue = streamingSizeValues[selectIndex];
cutomValueRect.height = 0;
}
else
{
if (!IsCustomValue(value))
{
value = Vector2Int.zero;
}
cutomValueRect.height = EditorGUIUtility.singleLineHeight;
newValue = EditorGUI.Vector2IntField(cutomValueRect, s_customValueLabel, value);
}
if (property.vector2IntValue != newValue)
{
if (Application.isPlaying)
{
var objectReferenceValue = property.serializedObject.targetObject;
var type = objectReferenceValue.GetType();
var attribute = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
var methodName = "SetTextureSize";
var method = type.GetMethod(methodName, attribute);
method.Invoke(objectReferenceValue, new object[] { newValue });
}
else
{
property.vector2IntValue = newValue;
}
}
var helpBoxRect = position;
helpBoxRect.y = cutomValueRect.y + cutomValueRect.height + EditorGUIUtility.standardVerticalSpacing;
helpBoxRect.height = EditorGUIUtility.singleLineHeight * 2;
EditorGUI.HelpBox(helpBoxRect, s_HelpBoxText, MessageType.Info);
EditorGUI.EndProperty();
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
if (property == null)
throw new System.ArgumentNullException(nameof(property));
var height = 0f;
// Popup.
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
// Custom values
Vector2Int value = property.vector2IntValue;
if (IsCustomValue(value))
{
height += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing;
}
//helpbox;
height += EditorGUIUtility.singleLineHeight * 2 + EditorGUIUtility.standardVerticalSpacing;
return height;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c55e741d09a34fedbb25a0f925106b25
timeCreated: 1637904184

View File

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

View File

@@ -0,0 +1,38 @@
#if URS_USE_HDRP_EDITOR
using UnityEngine; //Debug
using UnityEditor; //AssetPostProcessor
using UnityEngine.Rendering; //GraphicsSettings
#if UNITY_2019_3_OR_NEWER
using UnityEngine.Rendering.HighDefinition; //HDRenderPipelineAsset
#else
using UnityEngine.Experimental.Rendering.HDPipeline; //HDRenderPipelineAsset
#endif
namespace Unity.RenderStreaming.Editor
{
public class HDRPPostProcessor
{
[InitializeOnLoadMethod]
static void OnLoad()
{
if (null != GraphicsSettings.renderPipelineAsset)
{
return;
}
var allAssetPaths = AssetDatabase.GetAllAssetPaths();
foreach (var curAssetPath in allAssetPaths)
{
if (curAssetPath.EndsWith("HDRenderPipelineAsset.asset"))
{
HDRenderPipelineAsset pipelineAsset =
AssetDatabase.LoadAssetAtPath<HDRenderPipelineAsset>(curAssetPath);
GraphicsSettings.renderPipelineAsset = pipelineAsset;
PlayerSettings.colorSpace = ColorSpace.Linear;
}
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,34 @@
#if URS_USE_URS_EDITOR
using UnityEngine; //Debug
using UnityEditor; //AssetPostProcessor
using UnityEngine.Rendering; //GraphicsSettings
namespace Unity.RenderStreaming.Editor
{
public class URPInitialSetupPostProcessor
{
[InitializeOnLoadMethod]
static void OnLoad()
{
if (null != GraphicsSettings.renderPipelineAsset)
{
return;
}
var allAssetPaths = AssetDatabase.GetAllAssetPaths();
foreach (var curAssetPath in allAssetPaths)
{
if (curAssetPath.EndsWith("UniversalRenderPipelineAsset.asset"))
{
UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset pipelineAsset =
AssetDatabase.LoadAssetAtPath<UnityEngine.Rendering.Universal.UniversalRenderPipelineAsset>(
curAssetPath);
GraphicsSettings.renderPipelineAsset = pipelineAsset;
PlayerSettings.colorSpace = ColorSpace.Linear;
}
}
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,38 @@
using System;
namespace Unity.RenderStreaming.Editor
{
public static class RenderStreamingEditor
{
/// <summary>
///
/// </summary>
/// <param name="settings"></param>
/// <exception cref="ArgumentNullException"></exception>
public static void SetRenderStreamingSettings(RenderStreamingSettings settings)
{
if (settings == null)
{
throw new ArgumentNullException(nameof(settings));
}
RenderStreaming.Settings = settings;
}
/// <summary>
///
/// </summary>
/// <param name="settings"></param>
/// <exception cref="ArgumentNullException"></exception>
public static void SetSignalingSettings(SignalingSettings settings)
{
if (settings == null)
{
throw new ArgumentNullException(nameof(settings));
}
RenderStreaming.Settings.signalingSettings = settings;
RenderStreaming.ApplySettings();
}
}
}

View File

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

View File

@@ -0,0 +1,77 @@
using System.IO;
using UnityEditorInternal;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
internal class RenderStreamingProjectSettings : ScriptableObject
{
const string filePath = "ProjectSettings/RenderStreamingProjectSettings.asset";
[SerializeField] private bool m_WizardPopupAtStart = true;
[SerializeField] private bool m_WizardPopupAlreadyShownOnce = false;
public static bool wizardIsStartPopup
{
get => instance.m_WizardPopupAtStart;
set
{
instance.m_WizardPopupAtStart = value;
Save();
}
}
public static bool wizardPopupAlreadyShownOnce
{
get => instance.m_WizardPopupAlreadyShownOnce;
set
{
instance.m_WizardPopupAlreadyShownOnce = value;
Save();
}
}
static RenderStreamingProjectSettings s_Instance;
static RenderStreamingProjectSettings instance => s_Instance ? s_Instance : CreateOrLoad();
RenderStreamingProjectSettings()
{
s_Instance = this;
}
static RenderStreamingProjectSettings CreateOrLoad()
{
// Object loaded and created from this method.
// So RenderStreamingProjectSettings constructor is called implicitly.
// If RenderStreamingProjectSettings could be loaded, then s_Instance is assigned the loaded instance.
InternalEditorUtility.LoadSerializedFileAndForget(filePath);
if (s_Instance == null)
{
var created = CreateInstance<RenderStreamingProjectSettings>();
created.hideFlags = HideFlags.HideAndDontSave;
}
System.Diagnostics.Debug.Assert(s_Instance != null);
return s_Instance;
}
static void Save()
{
if (s_Instance == null)
{
RenderStreaming.Logger.Log("Cannot save ScriptableSingleton: no instance!");
return;
}
string folderPath = Path.GetDirectoryName(filePath);
if (!Directory.Exists(folderPath))
{
Directory.CreateDirectory(folderPath);
}
InternalEditorUtility.SaveToSerializedFileAndForget(new Object[] { s_Instance }, filePath,
allowTextSerialization: true);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b4f5b5e9819c4eafb84bd87d1c2f266f
timeCreated: 1673936399

View File

@@ -0,0 +1,196 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.RenderStreaming.Editor
{
internal class RenderStreamingProjectSettingsProvider : SettingsProvider
{
internal VisualElement rootVisualElement { get; private set; }
private bool isDefaultSettings => AssetDatabase.GetAssetPath(RenderStreaming.Settings) ==
RenderStreaming.DefaultRenderStreamingSettingsPath;
private bool noSettingsInAssets => availableRenderStreamingSettingsAssets.Length == 0
|| availableRenderStreamingSettingsAssets.All(x => x == RenderStreaming.DefaultRenderStreamingSettingsPath);
private string[] availableRenderStreamingSettingsAssets;
private int currentSelectedSettingsAsset;
private RenderStreamingSettings settings;
const string LabelRenderStreamingSettingsAsset = "Render Streaming Settings Asset";
const string LabelCreateSettingsButton = "Create New Settings Asset";
const string kSettingsPath = "Project/Render Streaming";
const string kTemplatePath = "Packages/com.unity.renderstreaming/Editor/UXML/RenderStreamingProjectSettings.uxml";
const string kStylePath = "Packages/com.unity.renderstreaming/Editor/Styles/RenderStreamingProjectSettings.uss";
[SettingsProvider]
public static SettingsProvider CreateProvider()
{
return new RenderStreamingProjectSettingsProvider(kSettingsPath, SettingsScope.Project, new List<string>()
{
L10n.Tr("experimental"),
L10n.Tr("streaming"),
L10n.Tr("webrtc"),
L10n.Tr("video"),
L10n.Tr("audio"),
});
}
public override void OnActivate(string searchContext, VisualElement rootElement)
{
var styleSheet = EditorGUIUtility.Load(kStylePath) as StyleSheet;
rootVisualElement = new ScrollView();
rootVisualElement.StretchToParentSize();
rootVisualElement.styleSheets.Add(styleSheet);
rootElement.Add(rootVisualElement);
var template = EditorGUIUtility.Load(kTemplatePath) as VisualTreeAsset;
VisualElement newVisualElement = new VisualElement();
template.CloneTree(newVisualElement);
rootVisualElement.Add(newVisualElement);
settings = RenderStreaming.Settings;
availableRenderStreamingSettingsAssets = FindRenderStreamingSettingsPathInProject();
var selectorContainer = rootVisualElement.Q<VisualElement>("renderStreamingSettingsSelector");
var defaultIndex = ArrayHelpers.IndexOf(availableRenderStreamingSettingsAssets, AssetDatabase.GetAssetPath(settings));
var choices = availableRenderStreamingSettingsAssets.ToList();
var selectPopup = new PopupField<string>(label: LabelRenderStreamingSettingsAsset, choices: choices, defaultIndex: defaultIndex)
{
name = "renderStreamingSettingsSelectPopup"
};
selectPopup.tooltip = "Choose the Render Streaming Settings.";
selectPopup.RegisterValueChangedCallback(evt =>
{
currentSelectedSettingsAsset = selectPopup.index;
var newSettings =
AssetDatabase.LoadAssetAtPath<RenderStreamingSettings>(availableRenderStreamingSettingsAssets[currentSelectedSettingsAsset]);
if (newSettings == settings)
{
return;
}
RenderStreaming.Settings = newSettings;
});
selectorContainer.Add(selectPopup);
var createSettingsButton = new Button { text = LabelCreateSettingsButton };
createSettingsButton.clicked += () =>
{
CreateNewSettingsAsset();
Repaint();
};
selectorContainer.Add(createSettingsButton);
var createAssetHelpBox = new HelpBox("Settings for the Render Streaming are not stored in an asset. Click the button above to create a settings asset you can edit.", HelpBoxMessageType.Info)
{
style = { display = noSettingsInAssets ? DisplayStyle.Flex : DisplayStyle.None }
};
selectorContainer.Add(createAssetHelpBox);
ShowRenderStreamingSettingsProperty();
// Disable UI when running in Playmode
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
if (EditorApplication.isPlaying)
rootVisualElement.SetEnabled(false);
}
public override void OnInspectorUpdate()
{
if (RenderStreaming.Settings == settings && settings != null)
{
return;
}
settings = RenderStreaming.Settings;
var index = ArrayHelpers.IndexOf(availableRenderStreamingSettingsAssets, AssetDatabase.GetAssetPath(settings));
rootVisualElement.Q<PopupField<string>>("renderStreamingSettingsSelectPopup").index = index;
ShowRenderStreamingSettingsProperty();
}
private static string[] FindRenderStreamingSettingsPathInProject()
{
var guids = AssetDatabase.FindAssets("t:RenderStreamingSettings");
return guids.Select(AssetDatabase.GUIDToAssetPath)
.Where(path => !path.StartsWith("Packages") || path.StartsWith(RenderStreaming.DefaultRenderStreamingSettingsPath))
.ToArray();
}
private static void CreateNewSettingsAsset()
{
// Query for file name.
var projectName = PlayerSettings.productName;
var path = EditorUtility.SaveFilePanel("Create Render Streaming Settings File", "Assets",
projectName, "asset");
if (string.IsNullOrEmpty(path))
return;
// Make sure the path is in the Assets/ folder.
var dataPath = Application.dataPath + "/";
if (!path.StartsWith(dataPath, StringComparison.CurrentCultureIgnoreCase))
{
RenderStreaming.Logger.Log(LogType.Error, $"Render Streaming settings must be stored in Assets folder of the project (got: '{path}')");
return;
}
// Make sure it ends with .asset.
var extension = Path.GetExtension(path);
if (string.Compare(extension, ".asset", StringComparison.InvariantCultureIgnoreCase) != 0)
path += ".asset";
// Create settings file.
var relativePath = "Assets/" + path.Substring(dataPath.Length);
CreateNewSettingsAsset(relativePath);
}
private static void CreateNewSettingsAsset(string relativePath)
{
var settings = ScriptableObject.CreateInstance<RenderStreamingSettings>();
AssetDatabase.CreateAsset(settings, relativePath);
EditorGUIUtility.PingObject(settings);
RenderStreaming.Settings = settings;
}
private void OnPlayModeStateChanged(PlayModeStateChange e)
{
switch (e)
{
case PlayModeStateChange.EnteredPlayMode:
rootVisualElement.SetEnabled(false);
break;
case PlayModeStateChange.ExitingPlayMode:
rootVisualElement.SetEnabled(true);
break;
}
}
private void ShowRenderStreamingSettingsProperty()
{
var settingsPropertyContainer = rootVisualElement.Q("settingsPropertyContainer");
settingsPropertyContainer.Clear();
var editor = UnityEditor.Editor.CreateEditor(settings);
var inspectorGUI = editor.CreateInspectorGUI();
inspectorGUI.SetEnabled(!isDefaultSettings);
inspectorGUI.Bind(editor.serializedObject);
if (!noSettingsInAssets && isDefaultSettings)
{
settingsPropertyContainer.Add(new HelpBox("This is package default settings. Please select other settings asset you can edit.", HelpBoxMessageType.Info));
}
settingsPropertyContainer.Add(inspectorGUI);
}
public RenderStreamingProjectSettingsProvider(string path, SettingsScope scopes, IEnumerable<string> keywords = null)
: base(path, scopes, keywords)
{
}
}
}

View File

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

View File

@@ -0,0 +1,50 @@
using System.Linq;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
namespace Unity.RenderStreaming.Editor
{
internal class RenderStreamingSettingBuildProvider : IPreprocessBuildWithReport, IPostprocessBuildWithReport
{
public int callbackOrder => 0;
public void OnPreprocessBuild(BuildReport report)
{
if (RenderStreaming.Settings == null)
return;
// If we operate on temporary object instead of input setting asset,
// adding temporary asset would result in preloadedAssets containing null object "{fileID: 0}".
// Hence we ignore adding temporary objects to preloaded assets.
if (!EditorUtility.IsPersistent(RenderStreaming.Settings))
return;
// Add InputSettings object assets, if it's not in there already.
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
if (!preloadedAssets.Contains(RenderStreaming.Settings))
{
ArrayHelpers.Append(ref preloadedAssets, RenderStreaming.Settings);
PlayerSettings.SetPreloadedAssets(preloadedAssets);
}
}
public void OnPostprocessBuild(BuildReport report)
{
// Revert back to original state by removing all render streaming settings from preloaded assets.
var preloadedAssets = PlayerSettings.GetPreloadedAssets();
while (preloadedAssets != null && preloadedAssets.Length > 0)
{
var target = preloadedAssets.FirstOrDefault(x => x is RenderStreamingSettings);
var index = ArrayHelpers.IndexOf(preloadedAssets, target);
if (index != -1)
{
ArrayHelpers.EraseAt(ref preloadedAssets, index);
PlayerSettings.SetPreloadedAssets(preloadedAssets);
}
else
break;
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 86410c7bcb6a49d39cff48607dc52eff
timeCreated: 1674615170

View File

@@ -0,0 +1,18 @@
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace Unity.RenderStreaming.Editor
{
[CustomEditor(typeof(RenderStreamingSettings))]
internal class RenderStreamingSettingsEditor : UnityEditor.Editor
{
public override VisualElement CreateInspectorGUI()
{
var root = new VisualElement();
root.Add(new PropertyField(serializedObject.FindProperty(RenderStreamingSettings.AutomaticStreamingPropertyName), "Automatic Streaming"));
root.Add(new PropertyField(serializedObject.FindProperty(RenderStreamingSettings.SignalingSettingsPropertyName), "Signaling Settings"));
return root;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 10aca1086d5f4165b559555ea5d48ef0
timeCreated: 1675058568

View File

@@ -0,0 +1,612 @@
using System;
using System.Linq;
using UnityEditor;
using UnityEditor.Callbacks;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Rendering;
using UnityEngine.UIElements;
namespace Unity.RenderStreaming.Editor
{
internal class RenderStreamingWizard : EditorWindow
{
private const string packageName = "com.unity.renderstreaming";
private static readonly BuildTarget[] supportedBuildTarget = {
BuildTarget.StandaloneWindows64,
BuildTarget.StandaloneOSX,
BuildTarget.StandaloneLinux64,
BuildTarget.iOS,
BuildTarget.Android
};
#if UNITY_2021_1_OR_NEWER
const AndroidSdkVersions RequiredAndroidSdkVersion = AndroidSdkVersions.AndroidApiLevel22;
#else
const AndroidSdkVersions RequiredAndroidSdkVersion = AndroidSdkVersions.AndroidApiLevel21;
#endif
private struct ConfigStyle
{
public readonly string label;
public readonly string error;
public readonly string button;
public readonly MessageType messageType;
public ConfigStyle(string label, string error, string button = "Fix",
MessageType messageType = MessageType.Error)
{
this.label = label;
this.error = error;
this.button = button;
this.messageType = messageType;
}
}
static readonly ConfigStyle runInBackground = new ConfigStyle(
label: "Run In Background",
error: "Run In Background must be True for Render Streaming to work in Background.");
static readonly ConfigStyle inputSystemSettingsAssets = new ConfigStyle(
label: "Input System Settings Assets",
error: "Input System Settings asset must exist under the Assets folder for changes.");
static readonly ConfigStyle inputSystemBackgroundBehavior = new ConfigStyle(
label: "InputSystem Background Behavior",
error: "InputSystem Background Behavior must be Ignore Focus for Input System to work in Background.");
static readonly ConfigStyle inputSystemPlayModeInputBehavior = new ConfigStyle(
label: "InputSystem PlayMode Input Behavior",
error: "InputSystem PlayMode Input behavior must be AllDeviceInputAlwaysGoesToGameView for InputSystem to work in background PlayMode.");
static readonly ConfigStyle currentBuildTarget = new ConfigStyle(
label: "Current BuildTarget platform",
error: "Current BuildTarget platform not supported.");
static readonly ConfigStyle currentGraphicsApi = new ConfigStyle(
label: "Current Graphics API",
error: "Current settings contains not support Graphics API.");
static readonly ConfigStyle macCameraUsageDescription = new ConfigStyle(
label: "macOS Camera Usage Description",
error: "Require Camera Usage Description for WebCam access on macOS.");
static readonly ConfigStyle macMicrophoneUsageDescription = new ConfigStyle(
label: "macOS Microphone Usage Description",
error: "Require Microphone Usage Description for Microphone access on macOS.");
static readonly ConfigStyle iOSCameraUsageDescription = new ConfigStyle(
label: "iOS Camera Usage Description",
error: "Require Camera Usage Description for WebCam access on iOS.");
static readonly ConfigStyle iOSMicrophoneUsageDescription = new ConfigStyle(
label: "iOS Microphone Usage Description",
error: "Require Microphone Usage Description for Microphone access on iOS.");
static readonly ConfigStyle androidMinimumAPILevel = new ConfigStyle(
label: "Android Minimum API Level",
error: $"The minimum Android SDK level required is {(int)RequiredAndroidSdkVersion} or higher.");
static readonly ConfigStyle androidScriptBackend = new ConfigStyle(
label: "Android Script Backend",
error: "Render Streaming only supports IL2CPP as a scripting backend.");
static readonly ConfigStyle androidTargetArchitecture = new ConfigStyle(
label: "Android Target Architecture",
error: "Render Streaming only supported ARM64 as a Android Target Architecture.");
static readonly ConfigStyle androidInternetAccess = new ConfigStyle(
label: "Android Internet Access",
error: "InternetAccess must be set Required on Android.");
enum Scope
{
PlayMode,
BuildSettings
}
struct Entry
{
public delegate bool Checker();
public delegate void Fixer();
public delegate bool DependChecker();
public readonly Scope scope;
public readonly ConfigStyle configStyle;
public readonly Checker check;
public readonly Fixer fix;
public readonly DependChecker dependChecker;
public readonly bool forceDisplayCheck;
public readonly bool skipErrorIcon;
public Entry(
Scope scope,
ConfigStyle configStyle,
Checker check,
Fixer fix,
DependChecker dependChecker = null,
bool forceDisplayCheck = false,
bool skipErrorIcon = false
)
{
this.scope = scope;
this.configStyle = configStyle;
this.check = check;
this.fix = fix;
this.dependChecker = dependChecker;
this.forceDisplayCheck = forceDisplayCheck;
this.skipErrorIcon = skipErrorIcon;
}
}
private Entry[] entries;
Entry[] Entries
{
get
{
// due to functor, cannot static link directly in an array and need lazy init
if (entries == null)
entries = new[]
{
new Entry(Scope.PlayMode, runInBackground, IsRunInBackgroundCorrect, FixRunInBackground),
new Entry(Scope.PlayMode, inputSystemSettingsAssets, IsInputSettingsAssetsExists, FixInputSettingsAssets),
new Entry(Scope.PlayMode, inputSystemBackgroundBehavior,
IsInputSystemBackgroundBehaviorCorrect,
FixInputSystemBackgroundBehavior,
IsInputSettingsAssetsExists),
new Entry(Scope.PlayMode, inputSystemPlayModeInputBehavior,
IsInputSystemPlayModeInputBehaviorCorrect,
FixInputSystemPlayModeInputBehavior,
IsInputSettingsAssetsExists),
new Entry(Scope.BuildSettings, currentBuildTarget, IsSupportedBuildTarget, FixSupportedBuildTarget),
new Entry(Scope.BuildSettings, currentGraphicsApi, IsSupportedGraphics, FixSupportedGraphics),
new Entry(Scope.BuildSettings, macCameraUsageDescription, IsMacCameraUsageCorrect, FixMacCameraUsage),
new Entry(Scope.BuildSettings, macMicrophoneUsageDescription, IsMacMicrophoneUsageCorrect,
FixMacMicrophoneUsage),
new Entry(Scope.BuildSettings, iOSCameraUsageDescription, IsIOSCameraUsageCorrect, FixIOSCameraUsage),
new Entry(Scope.BuildSettings, iOSMicrophoneUsageDescription, IsIOSMicrophoneUsageCorrect,
FixIOSMicrophoneUsage),
new Entry(Scope.BuildSettings, androidMinimumAPILevel, IsAndroidMinimumAPILevelCorrect,
FixAndroidMinimumAPILevel),
new Entry(Scope.BuildSettings, androidScriptBackend, IsAndroidScriptBackendCorrect,
FixAndroidScriptBackend),
new Entry(Scope.BuildSettings, androidTargetArchitecture, IsAndroidTargetArchitectureCorrect,
FixAndroidTargetArchitecture),
new Entry(Scope.BuildSettings, androidInternetAccess, IsAndroidInternetAccessCorrect,
FixAndroidInternetAccess),
};
return entries;
}
}
private static bool IsRunInBackgroundCorrect() => PlayerSettings.runInBackground;
private static void FixRunInBackground() => PlayerSettings.runInBackground = true;
private static bool IsInputSettingsAssetsExists()
{
var path = AssetDatabase.GetAssetPath(UnityEngine.InputSystem.InputSystem.settings);
return !string.IsNullOrEmpty(path) && path.StartsWith("Assets/");
}
private static void FixInputSettingsAssets()
{
var inputSettings = CreateInstance<InputSettings>();
AssetDatabase.CreateAsset(inputSettings, $"Assets/{PlayerSettings.productName}.inputsettings.asset");
UnityEngine.InputSystem.InputSystem.settings = inputSettings;
}
private static bool IsInputSystemBackgroundBehaviorCorrect() =>
UnityEngine.InputSystem.InputSystem.settings.backgroundBehavior == InputSettings.BackgroundBehavior.IgnoreFocus;
private static void FixInputSystemBackgroundBehavior()
{
UnityEngine.InputSystem.InputSystem.settings.backgroundBehavior = InputSettings.BackgroundBehavior.IgnoreFocus;
EditorUtility.SetDirty(UnityEngine.InputSystem.InputSystem.settings);
}
private static bool IsInputSystemPlayModeInputBehaviorCorrect() =>
UnityEngine.InputSystem.InputSystem.settings.editorInputBehaviorInPlayMode ==
InputSettings.EditorInputBehaviorInPlayMode.AllDeviceInputAlwaysGoesToGameView;
private static void FixInputSystemPlayModeInputBehavior()
{
UnityEngine.InputSystem.InputSystem.settings.editorInputBehaviorInPlayMode = InputSettings.EditorInputBehaviorInPlayMode.AllDeviceInputAlwaysGoesToGameView;
EditorUtility.SetDirty(UnityEngine.InputSystem.InputSystem.settings);
}
private static bool IsSupportedBuildTarget()
{
var correctBuildTarget = supportedBuildTarget.Contains(EditorUserBuildSettings.activeBuildTarget);
#if UNITY_2021_1_OR_NEWER
correctBuildTarget = correctBuildTarget && EditorUserBuildSettings.standaloneBuildSubtarget == StandaloneBuildSubtarget.Player;
#endif
return correctBuildTarget;
}
private static void FixSupportedBuildTarget()
{
BuildTarget target = default;
#if UNITY_EDITOR_WIN
target = BuildTarget.StandaloneWindows64;
#elif UNITY_EDITOR_OSX
target = BuildTarget.StandaloneOSX;
#elif UNITY_EDITOR_LINUX
target = BuildTarget.StandaloneLinux64;
#else
throw new NotSupportedException();
#endif
EditorUserBuildSettings.SwitchActiveBuildTarget(BuildPipeline.GetBuildTargetGroup(target), target);
#if UNITY_2021_1_OR_NEWER
EditorUserBuildSettings.standaloneBuildSubtarget = StandaloneBuildSubtarget.Player;
#endif
}
private static bool IsSupportedGraphics() => supportedBuildTarget.All(CheckGraphicsApi);
private static bool CheckGraphicsApi(BuildTarget target)
{
var targetGraphics = PlayerSettings.GetGraphicsAPIs(target);
switch (target)
{
case BuildTarget.StandaloneOSX:
case BuildTarget.iOS:
return targetGraphics.All(x => x == GraphicsDeviceType.Metal);
case BuildTarget.Android:
return targetGraphics.All(x => x == GraphicsDeviceType.OpenGLES3 || x == GraphicsDeviceType.Vulkan);
case BuildTarget.StandaloneWindows64:
return targetGraphics.All(x => x == GraphicsDeviceType.Direct3D11 || x == GraphicsDeviceType.Direct3D12 || x == GraphicsDeviceType.Vulkan);
case BuildTarget.StandaloneLinux64:
return targetGraphics.All(x => x == GraphicsDeviceType.OpenGLCore || x == GraphicsDeviceType.Vulkan);
default:
return false;
}
}
private static void FixSupportedGraphics()
{
foreach (var target in supportedBuildTarget.Where(x => !CheckGraphicsApi(x)))
{
switch (target)
{
case BuildTarget.StandaloneOSX:
case BuildTarget.iOS:
PlayerSettings.SetGraphicsAPIs(target, new[] { GraphicsDeviceType.Metal });
break;
case BuildTarget.Android:
PlayerSettings.SetGraphicsAPIs(target, new[] { GraphicsDeviceType.OpenGLES3, GraphicsDeviceType.Vulkan });
break;
case BuildTarget.StandaloneWindows64:
PlayerSettings.SetGraphicsAPIs(target, new[] { GraphicsDeviceType.Direct3D11, GraphicsDeviceType.Direct3D12, GraphicsDeviceType.Vulkan });
break;
case BuildTarget.StandaloneLinux64:
PlayerSettings.SetGraphicsAPIs(target, new[] { GraphicsDeviceType.OpenGLCore, GraphicsDeviceType.Vulkan });
break;
default:
throw new NotSupportedException($"{nameof(target)} is not supported.");
}
}
}
private static bool IsMacCameraUsageCorrect() =>
!string.IsNullOrEmpty(PlayerSettings.macOS.cameraUsageDescription);
private static void FixMacCameraUsage() => PlayerSettings.macOS.cameraUsageDescription = "For WebCamTexture";
private static bool IsMacMicrophoneUsageCorrect() =>
!string.IsNullOrEmpty(PlayerSettings.iOS.microphoneUsageDescription);
private static void FixMacMicrophoneUsage() => PlayerSettings.iOS.microphoneUsageDescription = "For Microphone";
private static bool IsIOSCameraUsageCorrect() =>
!string.IsNullOrEmpty(PlayerSettings.iOS.cameraUsageDescription);
private static void FixIOSCameraUsage() => PlayerSettings.iOS.cameraUsageDescription = "For WebCamTexture";
private static bool IsIOSMicrophoneUsageCorrect() =>
!string.IsNullOrEmpty(PlayerSettings.iOS.microphoneUsageDescription);
private static void FixIOSMicrophoneUsage() => PlayerSettings.iOS.microphoneUsageDescription = "For Microphone";
private static bool IsAndroidMinimumAPILevelCorrect() =>
PlayerSettings.Android.minSdkVersion >= RequiredAndroidSdkVersion;
private static void FixAndroidMinimumAPILevel() =>
PlayerSettings.Android.minSdkVersion = RequiredAndroidSdkVersion;
private static bool IsAndroidScriptBackendCorrect() =>
PlayerSettings.GetScriptingBackend(BuildTargetGroup.Android) == ScriptingImplementation.IL2CPP;
private static void FixAndroidScriptBackend() =>
PlayerSettings.SetScriptingBackend(BuildTargetGroup.Android, ScriptingImplementation.IL2CPP);
private static bool IsAndroidTargetArchitectureCorrect() =>
PlayerSettings.Android.targetArchitectures == AndroidArchitecture.ARM64;
private static void FixAndroidTargetArchitecture() =>
PlayerSettings.Android.targetArchitectures = AndroidArchitecture.ARM64;
private static bool IsAndroidInternetAccessCorrect() => PlayerSettings.Android.forceInternetPermission;
private static void FixAndroidInternetAccess() => PlayerSettings.Android.forceInternetPermission = true;
const string kTemplatePath = "Packages/com.unity.renderstreaming/Editor/UXML/RenderStreamingWizard.uxml";
const string kStylePath = "Packages/com.unity.renderstreaming/Editor/Styles/RenderStreamingWizard.uss";
[MenuItem("Window/Render Streaming/Render Streaming Wizard", priority = 10000)]
static void OpenWindow()
{
var window = GetWindow<RenderStreamingWizard>("Render Streaming Wizard");
window.minSize = new Vector2(500, 450);
RenderStreamingProjectSettings.wizardPopupAlreadyShownOnce = true;
}
static RenderStreamingWizard()
{
WizardBehaviour();
}
private static int frameToWait;
private static void WizardBehaviourDelayed()
{
if (frameToWait > 0)
--frameToWait;
else
{
EditorApplication.update -= WizardBehaviourDelayed;
if (RenderStreamingProjectSettings.wizardIsStartPopup &&
!RenderStreamingProjectSettings.wizardPopupAlreadyShownOnce)
{
//Application.isPlaying cannot be called in constructor. Do it here
if (Application.isPlaying)
return;
OpenWindow();
}
EditorApplication.quitting += () => RenderStreamingProjectSettings.wizardPopupAlreadyShownOnce = false;
}
}
[DidReloadScripts]
static void CheckPersistentPopupAlreadyOpened()
{
EditorApplication.delayCall += () =>
{
if (RenderStreamingProjectSettings.wizardPopupAlreadyShownOnce)
EditorApplication.quitting +=
() => RenderStreamingProjectSettings.wizardPopupAlreadyShownOnce = false;
};
}
[DidReloadScripts]
static void WizardBehaviour()
{
//We need to wait at least one frame or the popup will not show up
frameToWait = 10;
EditorApplication.update += WizardBehaviourDelayed;
}
private void OnEnable()
{
var styleSheet = EditorGUIUtility.Load(kStylePath) as StyleSheet;
var uiAsset = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(kTemplatePath);
var newVisualElement = new VisualElement();
uiAsset.CloneTree(newVisualElement);
rootVisualElement.Add(newVisualElement);
rootVisualElement.styleSheets.Add(styleSheet);
BindCheckVersion();
BindCurrentSettings();
BindChecker();
BindWebApp();
BindCheckBox();
}
private int inspectorCounter = 0;
private Label currentSettingsLabel;
private HelpBox currentSettingsHelpBox;
private Button fixAllButton;
private VisualElement playmodeCheckButtons;
private VisualElement buildSettingsCheckButtons;
private void OnInspectorUpdate()
{
// limit inspector update per 1 second.
inspectorCounter++;
if (inspectorCounter % 10 != 0)
{
return;
}
if (currentSettingsLabel != null)
{
currentSettingsLabel.text = $"Current Render Streaming Settings: {GetSettingsAssetName()}";
}
if (currentSettingsHelpBox != null)
{
currentSettingsHelpBox.style.display = IsDefaultSetting() ? DisplayStyle.Flex : DisplayStyle.None;
}
fixAllButton?.SetEnabled(entries.Any(x => !x.check()));
if (playmodeCheckButtons != null && buildSettingsCheckButtons != null)
{
foreach (var visualElement in playmodeCheckButtons.Children()
.Concat(buildSettingsCheckButtons.Children())
.Select(c => c as ConfigInfoLine)
.Where(c => c != null))
{
visualElement.CheckUpdate();
}
}
inspectorCounter = 0;
}
private void BindCheckVersion()
{
var checkUpdateContainer = rootVisualElement.Q("checkUpdateContainer");
var label = new TextElement { text = "Current Render Streaming version: checking..." };
checkUpdateContainer.Add(label);
var button = new Button(() =>
UnityEditor.PackageManager.UI.Window.Open(packageName))
{ text = "Check update" };
button.AddToClassList("right-anchored-button");
checkUpdateContainer.Add(button);
RequestJobManager.CreateListRequest(true, true, (req) =>
{
var packageInfo = req.FindPackage(packageName);
if (null == packageInfo)
{
RenderStreaming.Logger.Log(LogType.Error, $"Not found package \"{packageName}\"");
return;
}
label.text = $"Current Render Streaming version: {packageInfo.version}";
}, null);
}
private void BindCurrentSettings()
{
var checkUpdateContainer = rootVisualElement.Q("currentSettingsContainer");
currentSettingsLabel = new Label { text = $"Current Render Streaming Settings: {GetSettingsAssetName()}" };
currentSettingsLabel.AddToClassList("normal");
checkUpdateContainer.Add(currentSettingsLabel);
var button = new Button(() => SettingsService.OpenProjectSettings("Project/Render Streaming"))
{
text = "Open Project Settings"
};
button.AddToClassList(("open-project-settings"));
checkUpdateContainer.Add(button);
currentSettingsHelpBox = new HelpBox("Current selected settings is default. If you want to change settings, open the Project Window and create or select another Settings.", HelpBoxMessageType.Info)
{
style = { display = IsDefaultSetting() ? DisplayStyle.Flex : DisplayStyle.None }
};
checkUpdateContainer.Add(currentSettingsHelpBox);
}
private static string GetSettingsAssetName()
{
var path = AssetDatabase.GetAssetPath(RenderStreaming.Settings);
var assetName = path == RenderStreaming.DefaultRenderStreamingSettingsPath ? "Default" : path.Split('/').Last();
return assetName;
}
private static bool IsDefaultSetting()
{
return AssetDatabase.GetAssetPath(RenderStreaming.Settings) == RenderStreaming.DefaultRenderStreamingSettingsPath;
}
private void BindChecker()
{
fixAllButton = rootVisualElement.Q<Button>("fixAllButton");
playmodeCheckButtons = rootVisualElement.Q("playmodeCheckButtons");
buildSettingsCheckButtons = rootVisualElement.Q("buildSettingsCheckButtons");
fixAllButton.clickable.clicked += () =>
{
foreach (var entry in Entries.Where(x => !x.check()))
{
entry.fix();
}
};
foreach (var entry in Entries.Where(x => x.scope == Scope.PlayMode))
{
playmodeCheckButtons.Add(new ConfigInfoLine(
entry.configStyle.label,
entry.configStyle.error,
entry.configStyle.messageType,
entry.configStyle.button,
() => entry.check(),
entry.fix == null ? (Action)null : () => entry.fix(),
entry.dependChecker == null ? (Func<bool>)null : () => entry.dependChecker(),
entry.configStyle.messageType == MessageType.Error || entry.forceDisplayCheck,
entry.skipErrorIcon));
}
foreach (var entry in Entries.Where(x => x.scope == Scope.BuildSettings))
{
buildSettingsCheckButtons.Add(new ConfigInfoLine(
entry.configStyle.label,
entry.configStyle.error,
entry.configStyle.messageType,
entry.configStyle.button,
() => entry.check(),
entry.fix == null ? (Action)null : () => entry.fix(),
entry.dependChecker == null ? (Func<bool>)null : () => entry.dependChecker(),
entry.configStyle.messageType == MessageType.Error || entry.forceDisplayCheck,
entry.skipErrorIcon));
}
}
private void BindWebApp()
{
var webappContainer = rootVisualElement.Q("webappContainer");
var webappButton = new Button(() =>
{
WebAppDownloader.GetPackageVersion(packageName, (version) =>
{
var dstPath = EditorUtility.OpenFolderPanel("Select download folder", "", "");
WebAppDownloader.DownloadWebApp(version, dstPath, null);
});
})
{ text = "Download latest version web app." };
webappButton.AddToClassList("large-button");
var showWebAppDocButton = new Button(() =>
{
WebAppDownloader.GetPackageVersion(packageName, (version) =>
{
var url = WebAppDownloader.GetURLDocumentation(version);
Application.OpenURL(url);
});
})
{ text = "Show web app documentation." };
showWebAppDocButton.AddToClassList("large-button");
var showWebAppSourceButton = new Button(() =>
{
WebAppDownloader.GetPackageVersion(packageName, (version) =>
{
var url = WebAppDownloader.GetURLSourceCode(version);
Application.OpenURL(url);
});
})
{ text = "Show web app source code." };
showWebAppSourceButton.AddToClassList("large-button");
webappContainer.Add(webappButton);
webappContainer.Add(showWebAppDocButton);
webappContainer.Add(showWebAppSourceButton);
}
private void BindCheckBox()
{
var wizardCheckboxContainer = rootVisualElement.Q("wizardCheckboxContainer");
var wizardCheckbox = new Toggle("Show on start")
{
name = "wizardCheckbox"
};
wizardCheckbox.SetValueWithoutNotify(RenderStreamingProjectSettings.wizardIsStartPopup);
wizardCheckbox.RegisterValueChangedCallback(evt
=> RenderStreamingProjectSettings.wizardIsStartPopup = evt.newValue);
wizardCheckboxContainer.Add(wizardCheckbox);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ef2985d10f2c400a880dff790d3fdc55
timeCreated: 1673918762

View File

@@ -0,0 +1,33 @@
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.RenderStreaming.Editor
{
// todo(kazuki): workaround.
// ListView.reorderMode is not supported on Unity 2020.3.
internal class ReorderableListField : IMGUIContainer
{
private readonly ReorderableList reorderable;
public ReorderableListField(SerializedProperty property, string label)
{
reorderable = new ReorderableList(property.serializedObject, property)
{
drawElementCallback = (rect, index, isActive, isFocused) => EditorGUI.PropertyField(rect, property.GetArrayElementAtIndex(index)),
drawHeaderCallback = rect => EditorGUI.LabelField(rect, label)
};
onGUIHandler = OnGUIHandler;
}
void OnGUIHandler()
{
reorderable.DoLayoutList();
reorderable.serializedProperty.serializedObject.ApplyModifiedProperties();
}
}
}

View File

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

View File

@@ -0,0 +1,43 @@
using System.Collections.Generic; //IEnumerable
using UnityEditor.PackageManager; //PackageCollection
using UnityEditor.PackageManager.Requests; //ListRequest
namespace Unity.RenderStreaming.Editor
{
/// <summary>
/// An extension class to extend the functionalities of UnityEditor.PackageManager.Requests classes
/// </summary>
internal static class RequestExtensions
{
/// <summary>
/// Find a PackageInfo which has the passed parameter
/// </summary>
/// <param name="listRequest">list of <see cref="Request">Request</see> object</param>
/// <param name="packageName">the package name</param>
/// <returns>The PackageInfo if found, otherwise null</returns>
public static PackageInfo FindPackage(this Request<PackageCollection> listRequest, string packageName)
{
IEnumerable<PackageInfo> packageInfoCollection = listRequest.Result as IEnumerable<PackageInfo>;
if (null == packageInfoCollection)
{
return null;
}
var enumerator = packageInfoCollection.GetEnumerator();
while (enumerator.MoveNext())
{
PackageInfo curInfo = enumerator.Current;
if (curInfo.name == packageName)
{
return curInfo;
}
}
return null;
}
}
} //namespace Unity.RenderStreaming.Editor

View File

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

View File

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

View File

@@ -0,0 +1,22 @@
using System; //Action
using UnityEditor.PackageManager; //PackageInfo
using UnityEditor.PackageManager.Requests; //ListRequest, AddRequest, etc
namespace Unity.RenderStreaming.Editor
{
class AddRequestInfo
{
internal string PackageName;
internal Action<Request<PackageInfo>> OnSuccessAction;
internal Action<Request<PackageInfo>> OnFailAction;
internal AddRequestInfo(string packageName,
Action<Request<PackageInfo>> onSuccess, Action<Request<PackageInfo>> onFail)
{
PackageName = packageName;
OnSuccessAction = onSuccess;
OnFailAction = onFail;
}
}
} //namespace Unity.RenderStreaming.Editor

View File

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

View File

@@ -0,0 +1,25 @@
using System; //Action
using UnityEditor.PackageManager; //PackageCollection
using UnityEditor.PackageManager.Requests; //ListRequest, AddRequest, etc
namespace Unity.RenderStreaming.Editor
{
class ListRequestInfo
{
internal bool OfflineMode;
internal bool IncludeIndirectIndependencies;
internal Action<Request<PackageCollection>> OnSuccessAction;
internal Action<Request<PackageCollection>> OnFailAction;
internal ListRequestInfo(bool offlineMode, bool includeIndirectDependencies,
Action<Request<PackageCollection>> onSuccess, Action<Request<PackageCollection>> onFail)
{
OfflineMode = offlineMode;
IncludeIndirectIndependencies = includeIndirectDependencies;
OnSuccessAction = onSuccess;
OnFailAction = onFail;
}
}
} //namespace Unity.RenderStreaming.Editor

View File

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

View File

@@ -0,0 +1,21 @@
using System; //Action
namespace Unity.RenderStreaming.Editor
{
class RemoveRequestInfo
{
internal string PackageName;
internal Action OnSuccessAction;
internal Action OnFailAction;
internal RemoveRequestInfo(string packageName,
Action onSuccess, Action onFail)
{
PackageName = packageName;
OnSuccessAction = onSuccess;
OnFailAction = onFail;
}
}
} //namespace Unity.RenderStreaming.Editor

View File

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

View File

@@ -0,0 +1,23 @@
using System; //Action
using UnityEditor.PackageManager; //PackageInfo
using UnityEditor.PackageManager.Requests; //Request<T>
namespace Unity.RenderStreaming.Editor
{
class SearchAllRequestInfo
{
internal bool OfflineMode;
internal Action<Request<PackageInfo[]>> OnSuccessAction;
internal Action<Request<PackageInfo[]>> OnFailAction;
internal SearchAllRequestInfo(bool offlineMode,
Action<Request<PackageInfo[]>> onSuccess, Action<Request<PackageInfo[]>> onFail)
{
OfflineMode = offlineMode;
OnSuccessAction = onSuccess;
OnFailAction = onFail;
}
}
} //namespace Unity.RenderStreaming.Editor

View File

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

View File

@@ -0,0 +1,25 @@
using System; //Action
using UnityEditor.PackageManager; //PackageInfo
using UnityEditor.PackageManager.Requests; //Request<T>
namespace Unity.RenderStreaming.Editor
{
class SearchRequestInfo
{
internal string PackageName;
internal bool OfflineMode;
internal Action<Request<PackageInfo[]>> OnSuccessAction;
internal Action<Request<PackageInfo[]>> OnFailAction;
internal SearchRequestInfo(string packageName, bool offlineMode,
Action<Request<PackageInfo[]>> onSuccess, Action<Request<PackageInfo[]>> onFail)
{
PackageName = packageName;
OfflineMode = offlineMode;
OnSuccessAction = onSuccess;
OnFailAction = onFail;
}
}
} //namespace Unity.RenderStreaming.Editor

View File

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

View File

@@ -0,0 +1,144 @@
using System; //Action
using UnityEditor.PackageManager; //StatusCode
using UnityEditor.PackageManager.Requests; //Request
namespace Unity.RenderStreaming.Editor
{
//---------------------------------------------------------------------------------------------------------------------
//Non-generics version
internal class RequestJob : IRequestJob
{
internal RequestJob(Request req, Action onSuccess, Action onFail)
{
m_request = req;
m_onSuccess = onSuccess;
m_onFail = onFail;
}
//---------------------------------------------------------------------------------------------------------------------
public StatusCode Update()
{
if (null == m_request)
{
OnFail();
return StatusCode.Failure;
}
if (m_request.IsCompleted)
{
if (StatusCode.Success == m_request.Status)
{
OnSuccess();
return StatusCode.Success;
}
else
{
OnFail();
return StatusCode.Failure;
}
}
return StatusCode.InProgress;
}
//---------------------------------------------------------------------------------------------------------------------
void OnSuccess()
{
if (null == m_onSuccess)
return;
m_onSuccess();
}
//---------------------------------------------------------------------------------------------------------------------
void OnFail()
{
if (null == m_onFail)
return;
m_onFail();
}
Request m_request;
Action m_onSuccess;
Action m_onFail;
} //end RequestJob (non-generics version)
//---------------------------------------------------------------------------------------------------------------------
//RequestJob (generics version)
//Examples of T: PackageCollection(from ListRequest), PackageInfo (from AddRequest)
internal class RequestJob<T> : IRequestJob
{
internal RequestJob(Request<T> req, Action<Request<T>> onSuccess, Action<Request<T>> onFail)
{
m_request = req;
m_onSuccess = onSuccess;
m_onFail = onFail;
}
//---------------------------------------------------------------------------------------------------------------------
public StatusCode Update()
{
if (null == m_request)
{
OnFail();
return StatusCode.Failure;
}
if (m_request.IsCompleted)
{
if (StatusCode.Success == m_request.Status)
{
OnSuccess();
return StatusCode.Success;
}
else
{
OnFail();
return StatusCode.Failure;
}
}
return StatusCode.InProgress;
}
//---------------------------------------------------------------------------------------------------------------------
void OnSuccess()
{
if (null == m_onSuccess)
return;
m_onSuccess(m_request);
}
//---------------------------------------------------------------------------------------------------------------------
void OnFail()
{
if (null == m_onFail)
return;
m_onFail(m_request);
}
//---------------------------------------------------------------------------------------------------------------------
Request<T> m_request;
Action<Request<T>> m_onSuccess;
Action<Request<T>> m_onFail;
}
} //Unity.RenderStreaming.Editor

View File

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

View File

@@ -0,0 +1,207 @@
using System; //Action
using System.Collections.Generic; //HashSet
using UnityEditor.PackageManager; //PackageCollection
using UnityEditor.PackageManager.Requests; //ListRequest, AddRequest, etc
namespace Unity.RenderStreaming.Editor
{
/// <summary>
/// An editor class to manage requests to UnityEditor.PackageManager.Client
/// This class will perform its operations in background while Unity is running.
/// </summary>
internal class RequestJobManager
{
[UnityEditor.InitializeOnLoadMethod]
static void OnLoad()
{
UnityEditor.EditorApplication.update += UpdateRequestJobs;
}
//---------------------------------------------------------------------------------------------------------------------
/// <summary>
/// Queue a job to list the packages the project depends on.
/// </summary>
/// <param name="offlineMode">Specifies whether or not the Package Manager requests the latest information about
/// the project's packages from the remote Unity package registry. When offlineMode is true,
/// the PackageInfo objects in the PackageCollection returned by the Package Manager contain information
/// obtained from the local package cache, which could be out of date.</param>
/// <param name="includeIndirectIndependencies">Set to true to include indirect dependencies in the
/// PackageCollection returned by the Package Manager. Indirect dependencies include packages referenced
/// in the manifests of project packages or in the manifests of other indirect dependencies. Set to false
/// to include only the packages listed directly in the project manifest.</param>
/// <param name="onSuccess">Action which is executed if the request succeeded</param>
/// <param name="onFail">Action which is executed if the request failed </param>
///
public static void CreateListRequest(bool offlineMode, bool includeIndirectIndependencies,
Action<Request<PackageCollection>> onSuccess, Action<Request<PackageCollection>> onFail)
{
m_pendingListRequests.Enqueue(new ListRequestInfo(offlineMode, includeIndirectIndependencies, onSuccess, onFail));
}
//---------------------------------------------------------------------------------------------------------------------
/// <summary>
/// Queue a job to add a package dependency to the project.
/// </summary>
/// <param name="packageName">The name or ID of the package to add. If only the name is specified,
/// the latest version of the package is installed.</param>
/// <param name="onSuccess">Action which is executed if the request succeeded</param>
/// <param name="onFail">Action which is executed if the request failed </param>
///
public static void CreateAddRequest(string packageName,
Action<Request<PackageInfo>> onSuccess, Action<Request<PackageInfo>> onFail)
{
m_pendingAddRequests.Enqueue(new AddRequestInfo(packageName, onSuccess, onFail));
}
//---------------------------------------------------------------------------------------------------------------------
/// <summary>
/// Queue a job to removes a previously added package from the project.
/// </summary>
/// <param name="packageName">The name or ID of the package to add. </param>
/// <param name="onSuccess">Action which is executed if the request succeeded</param>
/// <param name="onFail">Action which is executed if the request failed </param>
///
public static void CreateRemoveRequest(string packageName, Action onSuccess, Action onFail)
{
m_pendingRemoveRequests.Enqueue(new RemoveRequestInfo(packageName, onSuccess, onFail));
}
//---------------------------------------------------------------------------------------------------------------------
/// <summary>
/// Queue a job to searches the Unity package registry for the given package.
/// </summary>
/// <param name="packageName">The name or ID of the package to add.</param>
/// <param name="offlineMode">Specifies whether or not the Package Manager requests the latest information about
/// the project's packages from the remote Unity package registry. When offlineMode is true,
/// the PackageInfo objects in the PackageCollection returned by the Package Manager contain information
/// obtained from the local package cache, which could be out of date.</param>
/// <param name="onSuccess">Action which is executed if the request succeeded</param>
/// <param name="onFail">Action which is executed if the request failed </param>
///
public static void CreateSearchRequest(string packageName, bool offlineMode,
Action<Request<PackageInfo[]>> onSuccess, Action<Request<PackageInfo[]>> onFail)
{
m_pendingSearchRequests.Enqueue(new SearchRequestInfo(packageName, offlineMode, onSuccess, onFail));
}
//---------------------------------------------------------------------------------------------------------------------
/// <summary>
/// Queue a job to search the Unity package registry for all packages compatible with the current Unity version.
/// </summary>
/// <param name="offlineMode">Specifies whether or not the Package Manager requests the latest information about
/// the project's packages from the remote Unity package registry. When offlineMode is true,
/// the PackageInfo objects in the PackageCollection returned by the Package Manager contain information
/// obtained from the local package cache, which could be out of date.</param>
/// <param name="onSuccess">Action which is executed if the request succeeded</param>
/// <param name="onFail">Action which is executed if the request failed </param>
///
public static void CreateSearchAllRequest(bool offlineMode,
Action<Request<PackageInfo[]>> onSuccess, Action<Request<PackageInfo[]>> onFail)
{
m_pendingSearchAllRequests.Enqueue(new SearchAllRequestInfo(offlineMode, onSuccess, onFail));
}
//---------------------------------------------------------------------------------------------------------------------
static void UpdateRequestJobs()
{
{ //Process pending list requests
var enumerator = m_pendingListRequests.GetEnumerator();
while (enumerator.MoveNext())
{
ListRequestInfo info = enumerator.Current;
ListRequest listReq = Client.List(info.OfflineMode, info.IncludeIndirectIndependencies);
m_requestJobs.Add(new RequestJob<PackageCollection>(listReq, info.OnSuccessAction, info.OnFailAction));
}
m_pendingListRequests.Clear();
}
{ //Process pending addrequests
var enumerator = m_pendingAddRequests.GetEnumerator();
while (enumerator.MoveNext())
{
AddRequestInfo info = enumerator.Current;
AddRequest addReq = Client.Add(info.PackageName);
m_requestJobs.Add(new RequestJob<PackageInfo>(addReq, info.OnSuccessAction, info.OnFailAction));
}
m_pendingAddRequests.Clear();
}
{ //Process pending RemoveRequests
var enumerator = m_pendingRemoveRequests.GetEnumerator();
while (enumerator.MoveNext())
{
RemoveRequestInfo info = enumerator.Current;
RemoveRequest removeReq = Client.Remove(info.PackageName);
m_requestJobs.Add(new RequestJob(removeReq, info.OnSuccessAction, info.OnFailAction));
}
m_pendingRemoveRequests.Clear();
}
{ //Process pending SearchRequests
var enumerator = m_pendingSearchRequests.GetEnumerator();
while (enumerator.MoveNext())
{
SearchRequestInfo info = enumerator.Current;
SearchRequest searchReq = Client.Search(info.PackageName, info.OfflineMode);
m_requestJobs.Add(new RequestJob<PackageInfo[]>(searchReq, info.OnSuccessAction, info.OnFailAction));
}
m_pendingSearchRequests.Clear();
}
{ //Process pending SearchAllRequests
var enumerator = m_pendingSearchAllRequests.GetEnumerator();
while (enumerator.MoveNext())
{
SearchAllRequestInfo info = enumerator.Current;
SearchRequest searchReq = Client.SearchAll(info.OfflineMode);
m_requestJobs.Add(new RequestJob<PackageInfo[]>(searchReq, info.OnSuccessAction, info.OnFailAction));
}
m_pendingSearchAllRequests.Clear();
}
{ //Update and register completed jobs
var enumerator = m_requestJobs.GetEnumerator();
while (enumerator.MoveNext())
{
StatusCode code = enumerator.Current.Update();
if (StatusCode.Failure == code || StatusCode.Success == code)
{
m_jobsToDelete.Add(enumerator.Current);
}
}
}
{ //delete completed jobs
var enumerator = m_jobsToDelete.GetEnumerator();
while (enumerator.MoveNext())
{
m_requestJobs.Remove(enumerator.Current);
}
m_jobsToDelete.Clear();
}
}
//---------------------------------------------------------------------------------------------------------------------
static Queue<ListRequestInfo> m_pendingListRequests = new Queue<ListRequestInfo>();
static Queue<AddRequestInfo> m_pendingAddRequests = new Queue<AddRequestInfo>();
static Queue<RemoveRequestInfo> m_pendingRemoveRequests = new Queue<RemoveRequestInfo>();
static Queue<SearchRequestInfo> m_pendingSearchRequests = new Queue<SearchRequestInfo>();
static Queue<SearchAllRequestInfo> m_pendingSearchAllRequests = new Queue<SearchAllRequestInfo>();
static System.Collections.Generic.HashSet<IRequestJob> m_requestJobs = new HashSet<IRequestJob>();
static System.Collections.Generic.List<IRequestJob> m_jobsToDelete = new List<IRequestJob>();
}
} //namespace Unity.RenderStreaming.Editor

View File

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

View File

@@ -0,0 +1,22 @@
using UnityEditor;
namespace Unity.RenderStreaming.Editor
{
static class SerializedPropertyExtension
{
public static SerializedProperty FindPropertyInChildren(this SerializedProperty target, string propertyName)
{
SerializedProperty property = null;
while (target.Next(true))
{
if (target.name == propertyName)
{
property = target.Copy();
break;
}
}
target.Reset();
return property;
}
}
}

View File

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

View File

@@ -0,0 +1,243 @@
using System;
using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
namespace Unity.RenderStreaming.Editor
{
/// <summary>
/// Render Streaming inspector.
/// </summary>
[CustomEditor(typeof(SignalingManager))]
internal class SignalingManagerEditor : UnityEditor.Editor
{
const string DefaultSignalingSettingsSavePath =
"Assets/SignalingSettings.asset";
const string DefaultSignalingSettingsLoadPath =
"Packages/com.unity.renderstreaming/Runtime/SignalingSettings.asset";
SerializedProperty m_UseDefault;
SerializedProperty m_SignalingSettingsObject;
SerializedProperty m_SignalingSettings;
SerializedProperty m_Handlers;
SerializedProperty m_RunOnAwake;
SerializedProperty m_EvaluateCommandlineArguments;
VisualElement root;
Button openProjectSettingsButton;
PopupField<SignalingSettingsObject> signalingSettingsPopupField;
PropertyField signalingSettingsField;
private void OnEnable()
{
EditorApplication.projectChanged += OnProjectChanged;
m_UseDefault = serializedObject.FindProperty(SignalingManager.UseDefaultPropertyName);
m_SignalingSettingsObject = serializedObject.FindProperty(SignalingManager.SignalingSettingsObjectPropertyName);
m_SignalingSettings = serializedObject.FindProperty(SignalingManager.SignalingSettingsPropertyName);
m_Handlers = serializedObject.FindProperty(SignalingManager.HandlersPropertyName);
m_RunOnAwake = serializedObject.FindProperty(SignalingManager.RunOnAwakePropertyName);
m_EvaluateCommandlineArguments = serializedObject.FindProperty(SignalingManager.EvaluateCommandlineArgumentsPropertyName);
}
private void OnDisable()
{
EditorApplication.projectChanged -= OnProjectChanged;
}
public override VisualElement CreateInspectorGUI()
{
root = new VisualElement();
bool useDefault = m_UseDefault.boolValue;
var useDefaultField = new PropertyField(m_UseDefault, "Use Default Settings in Project Settings");
useDefaultField.RegisterValueChangeCallback(OnChangeUseDefault);
openProjectSettingsButton = new Button { text = "Open Project Setings" };
openProjectSettingsButton.clicked += OnClickedOpenProjectSettingsButton;
signalingSettingsPopupField = CreatePopUpSignalingType(m_SignalingSettingsObject, "Signaling Settings Asset");
signalingSettingsPopupField.RegisterValueChangedCallback(OnValueChangeSignalingSettingsObject);
signalingSettingsField = new PropertyField(m_SignalingSettings, "Signaling Settings");
signalingSettingsField.RegisterValueChangeCallback(OnValueChangeSignalingSettings);
root.Add(useDefaultField);
root.Add(openProjectSettingsButton);
root.Add(signalingSettingsPopupField);
root.Add(signalingSettingsField);
if (useDefault)
{
signalingSettingsPopupField.style.display = DisplayStyle.None;
signalingSettingsField.style.display = DisplayStyle.None;
}
else
{
openProjectSettingsButton.style.display = DisplayStyle.None;
}
root.Add(new ReorderableListField(m_Handlers, "Signaling Handler List"));
root.Add(new PropertyField(m_RunOnAwake, "Run On Awake"));
root.Add(new PropertyField(m_EvaluateCommandlineArguments, "Evaluate Commandline Arguments"));
// Disable UI when running in Playmode
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
if (EditorApplication.isPlaying)
root.SetEnabled(false);
return root;
}
PopupField<SignalingSettingsObject> CreatePopUpSignalingType(SerializedProperty property, string label)
{
var asset = property.objectReferenceValue as SignalingSettingsObject;
var paths = GetAvailableSignalingSettingsPath();
var field = new PopupField<SignalingSettingsObject>(label: label);
field.tooltip = "Choose the signaling settings.";
field.formatSelectedValueCallback = v => AssetDatabase.GetAssetPath(v);
field.formatListItemCallback = v => AssetDatabase.GetAssetPath(v);
if (paths.Length == 0)
return field;
var availableObjects = paths.Select(path => AssetDatabase.LoadAssetAtPath<SignalingSettingsObject>(path)).ToArray();
var defaultIndex = ArrayHelpers.IndexOf(availableObjects, asset);
field.choices = availableObjects.ToList();
field.index = defaultIndex < 0 ? 0 : defaultIndex;
return field;
}
static string[] GetAvailableSignalingSettingsPath()
{
var guids = AssetDatabase.FindAssets("t:SignalingSettingsObject");
return guids.Select(AssetDatabase.GUIDToAssetPath).Where(_ => _.StartsWith("Assets")).ToArray();
}
static bool IsValidSignalingSettingsObject(SignalingSettingsObject asset)
{
if (asset == null)
return false;
if (AssetDatabase.GetAssetPath(asset).IndexOf("Assets", StringComparison.Ordinal) != 0)
return false;
return true;
}
void CreateDefaultSignalingSettings()
{
// Create Default SignalingSettings in Assets folder when the useDefault flag is turned off first time.
SignalingSettingsObject asset = AssetDatabase.LoadAssetAtPath<SignalingSettingsObject>(DefaultSignalingSettingsSavePath);
if (asset == null)
{
if (!AssetDatabase.CopyAsset(DefaultSignalingSettingsLoadPath, DefaultSignalingSettingsSavePath))
{
RenderStreaming.Logger.Log(LogType.Error, "CopyAssets is failed.");
return;
}
asset = AssetDatabase.LoadAssetAtPath<SignalingSettingsObject>(DefaultSignalingSettingsSavePath);
}
var handler = serializedObject.targetObject as SignalingManager;
handler.signalingSettingsObject = asset;
handler.SetSignalingSettings(handler.signalingSettingsObject.settings);
}
private void OnPlayModeStateChanged(PlayModeStateChange e)
{
switch (e)
{
case PlayModeStateChange.EnteredPlayMode:
root.SetEnabled(false);
break;
case PlayModeStateChange.ExitingPlayMode:
root.SetEnabled(true);
break;
}
}
private void OnProjectChanged()
{
if (root == null)
return;
var paths = GetAvailableSignalingSettingsPath();
// Force to use default settings if there are no available settings in project folder.
if (paths.Length == 0)
{
m_UseDefault.boolValue = true;
serializedObject.ApplyModifiedProperties();
return;
}
var asset = m_SignalingSettingsObject.objectReferenceValue;
var availableObjects = paths.Select(path => AssetDatabase.LoadAssetAtPath<SignalingSettingsObject>(path)).ToArray();
var defaultIndex = ArrayHelpers.IndexOf(availableObjects, asset);
if (defaultIndex < 0)
{
defaultIndex = 0;
using var e = ChangeEvent<SignalingSettingsObject>.GetPooled(null, availableObjects[defaultIndex]);
e.target = signalingSettingsPopupField;
root.SendEvent(e);
}
signalingSettingsPopupField.choices = availableObjects.ToList();
signalingSettingsPopupField.index = defaultIndex;
}
private void OnClickedOpenProjectSettingsButton()
{
SettingsService.OpenProjectSettings("Project/Render Streaming");
}
private void OnChangeUseDefault(SerializedPropertyChangeEvent e)
{
bool useDefault = e.changedProperty.boolValue;
if (useDefault)
{
signalingSettingsPopupField.style.display = DisplayStyle.None;
signalingSettingsField.style.display = DisplayStyle.None;
openProjectSettingsButton.style.display = DisplayStyle.Flex;
}
else
{
signalingSettingsPopupField.style.display = DisplayStyle.Flex;
signalingSettingsField.style.display = DisplayStyle.Flex;
openProjectSettingsButton.style.display = DisplayStyle.None;
if (!IsValidSignalingSettingsObject(m_SignalingSettingsObject.objectReferenceValue as SignalingSettingsObject))
{
CreateDefaultSignalingSettings();
}
}
}
private void OnValueChangeSignalingSettingsObject(ChangeEvent<SignalingSettingsObject> e)
{
var asset = e.newValue;
if (asset == null)
{
RenderStreaming.Logger.Log(LogType.Error, "Setting None is not allowed for this parameter. Reverted.");
return;
}
if (AssetDatabase.GetAssetPath(asset).IndexOf("Assets", StringComparison.Ordinal) != 0)
{
RenderStreaming.Logger.Log(LogType.Error, "Setting an asset not placed under Assets folder is not allowed for this parameter. Reverted.");
return;
}
m_SignalingSettingsObject.objectReferenceValue = asset;
serializedObject.ApplyModifiedProperties();
var handler = serializedObject.targetObject as SignalingManager;
handler.SetSignalingSettings(asset.settings);
// Send event to repaint SignalingSettingsDrawer.
using SerializedPropertyChangeEvent changeEvent = SerializedPropertyChangeEvent.GetPooled();
changeEvent.changedProperty = m_SignalingSettingsObject;
changeEvent.target = signalingSettingsField.Children().First();
root.SendEvent(changeEvent);
}
private void OnValueChangeSignalingSettings(SerializedPropertyChangeEvent e)
{
// Update SignalingSettings in ScriptableObject.
var handler = serializedObject.targetObject as SignalingManager;
if (handler.signalingSettingsObject != null)
handler.signalingSettingsObject.settings = handler.GetSignalingSettings();
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,38 @@
.unity-label {
margin: 2px 4px;
padding: 1px 2px 2px 2px;
}
.font-small {
font-size: env(--unity-font-size-small);
}
.font-big {
font-size: env(--unity-font-size);
}
:root #unity-content-container {
min-width: 400px;
}
#titleLabel {
font-size: 19px;
-unity-font-style: bold;
padding-top: 0;
}
#renderStreamingContainer {
padding-left: 5px;
}
Foldout {
background-color: var(--unity-colors-inspector_titlebar-background-hover);
border-width: 1px;
border-color: var(--unity-colors-app_toolbar-background);
margin: 2px 9px 2px 6px;
min-width: 330px;
}
Foldout Label {
margin: 2px 0 0 3px;
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f59eb35823ffa674a9684802c2866fc0
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 12385, guid: 0000000000000000e000000000000000, type: 0}
disableValidation: 0

View File

@@ -0,0 +1,118 @@
#checkUpdateContainer {
flex-direction: row;
margin-top: 10px;
padding-top: 3px;
padding-bottom: 3px;
padding-left: 3px;
}
#wizardCheckbox {
margin-top: 15px;
margin-left: 20px;
margin-bottom: 20px;
}
#statusOK, #statusError {
width: 12px;
height: 12px;
position: absolute;
right: 10px;
}
#testLabel {
width: 425px;
padding-left: 15px;
}
#testRow {
flex-direction: row;
margin-top: 5px;
}
#resolver {
position: absolute;
right: 0px;
width: 100px;
margin-top: -4px;
}
.unity-help-box {
margin: 10px;
margin-top: 5px;
padding: 10px;
border-width: 1px;
border-radius: 3px;
flex-direction: row;
flex-shrink: 1;
}
.unity-help-box > Image {
margin-top: -7px;
margin-bottom: -7px;
margin-right: 10px;
flex-shrink: 0;
width: 32px;
height: 32px;
align-self: center;
}
.unity-help-box > Label {
-unity-text-align: middle-left;
white-space: normal;
margin-right: 32px;
}
.fix-all, .open-project-settings {
margin: 10px 20px;
}
.inner-box {
padding: 10px;
padding-top: 5px;
border-radius: 3px;
border-width: 1px;
}
.scope-box {
border-width: 1px;
border-radius: 3px;
margin: 0px;
margin-top: 12px;
padding: 7px;
}
.scope-box > #title {
align-self: center;
width: 200px;
font-size: 14px;
-unity-font-style: bold;
-unity-text-align: middle-center;
}
.right-anchored-button {
position: absolute;
right: 0px;
width: 114px;
margin-top: 0px;
margin-right: 10px;
}
.large-button {
margin-left: 20px;
margin-right: 20px;
}
.h1 {
-unity-font-style: bold;
font-size: 16px;
margin: 2px 5px 8px 9px;
}
.h2 {
-unity-font-style: bold;
margin-left: 7px;
}
.normal {
margin-left: 10px;
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d3f11d2dbfc14439b2866e1e72e0e4e6
timeCreated: 1673943091

View File

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

View File

@@ -0,0 +1,7 @@
<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:VisualElement name="renderStreamingContainer">
<ui:Label text="Render Streaming" name="titleLabel"/>
<ui:VisualElement name="renderStreamingSettingsSelector" />
<ui:VisualElement name="settingsPropertyContainer" />
</ui:VisualElement>
</ui:UXML>

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 310fa75d749d10549a0b61accad9c37d
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@@ -0,0 +1,23 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements"
xmlns:urs="Unity.RenderStreaming.Editor.UI"
xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements"
noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
<ui:ScrollView name="renderStreamingWizardContainer">
<ui:VisualElement class="normal" name="checkUpdateContainer"/>
<ui:VisualElement class="scope-box" name="currentSettingsContainer">
<ui:Label class="h1" text="Project Settings"/>
</ui:VisualElement>
<ui:VisualElement class="scope-box" name="configurationCheckingContainer">
<ui:Label class="h1" text="Configuration Checking"/>
<ui:Button class="fix-all" name="fixAllButton" text="Fix All"/>
<ui:Label class="h2" name="title" text="Playmode Settings"/>
<ui:VisualElement class="inner-box" name="playmodeCheckButtons"/>
<ui:Label class="h2" name="title" text="Build Settings"/>
<ui:VisualElement class="inner-box" name="buildSettingsCheckButtons"/>
</ui:VisualElement>
<ui:VisualElement class="scope-box normal" name="webappContainer">
<ui:Label class="h1" text="WebApp"/>
</ui:VisualElement>
<ui:VisualElement name="wizardCheckboxContainer" />
</ui:ScrollView>
</ui:UXML>

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 616659ab6b4f4e4e935ec9b1754bbc2f
timeCreated: 1673919559

View File

@@ -0,0 +1,32 @@
{
"name": "Unity.RenderStreaming.Editor",
"rootNamespace": "",
"references": [
"GUID:40a5acf76f04c4c8ebb69605e4b0d5c7",
"GUID:75469ad4d38634e559750d17036d5f7c",
"GUID:457756d89b35d2941b3e7b37b4ece6f1",
"GUID:15fc0a57446b3144c949da3e2b9737a9"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.unity.render-pipelines.high-definition",
"expression": "",
"define": "URS_USE_HDRP_EDITOR"
},
{
"name": "com.unity.render-pipelines.universal",
"expression": "",
"define": "URS_USE_URS_EDITOR"
}
],
"noEngineReferences": false
}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 7e479a0c97f111c48b6a279fad867f28
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,76 @@
#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomEditor(typeof(VideoStreamReceiver))]
[CanEditMultipleObjects]
internal class VideoStreamReceiverEditor : UnityEditor.Editor
{
SerializedProperty m_codec;
SerializedProperty m_renderMode;
SerializedProperty m_targetTexture;
static AnimBool[] m_renderModeFade;
void OnEnable()
{
m_codec = serializedObject.FindProperty(VideoStreamReceiver.CodecPropertyName);
m_renderMode = serializedObject.FindProperty(VideoStreamReceiver.RenderModePropertyName);
m_targetTexture = serializedObject.FindProperty(VideoStreamReceiver.TargetTexturePropertyName);
if (m_renderModeFade == null)
{
m_renderModeFade = new AnimBool[Enum.GetValues(typeof(VideoRenderMode)).Length];
for (int i = 0; i < m_renderModeFade.Length; i++)
m_renderModeFade[i] = new AnimBool(i == m_renderMode.intValue);
}
Array.ForEach(m_renderModeFade, anim => anim.valueChanged.AddListener(Repaint));
}
void OnDisable()
{
Array.ForEach(m_renderModeFade, anim => anim.valueChanged.RemoveListener(Repaint));
}
public override void OnInspectorGUI()
{
serializedObject.Update();
bool disableEditMediaSource = Application.isPlaying;
/// todo(kazuki): Make available to change video source parameters in runtime.
using (new EditorGUI.DisabledScope(disableEditMediaSource))
{
EditorGUILayout.PropertyField(m_renderMode);
HandleDataSourceField();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_codec);
}
serializedObject.ApplyModifiedProperties();
}
private void HandleDataSourceField()
{
for (var i = 0; i < m_renderModeFade.Length; i++)
m_renderModeFade[i].target = m_renderMode.intValue == i;
if (EditorGUILayout.BeginFadeGroup(m_renderModeFade[(int)VideoRenderMode.APIOnly].faded))
{
}
EditorGUILayout.EndFadeGroup();
if (EditorGUILayout.BeginFadeGroup(m_renderModeFade[(int)VideoRenderMode.RenderTexture].faded))
{
EditorGUILayout.PropertyField(m_targetTexture);
}
EditorGUILayout.EndFadeGroup();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,139 @@
#if UNITY_EDITOR
using System;
using UnityEditor;
using UnityEditor.AnimatedValues;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
[CustomEditor(typeof(VideoStreamSender))]
[CanEditMultipleObjects]
internal class VideoStreamSenderEditor : UnityEditor.Editor
{
class Styles
{
public readonly GUIContent sourceContent =
EditorGUIUtility.TrTextContent("Video Source Type", "Type of source the video will be streamed.");
public readonly GUIContent frameRateContent =
EditorGUIUtility.TrTextContent("Frame rate", "A value affects loads on the encoding thread.");
public readonly GUIContent bitrateContent =
EditorGUIUtility.TrTextContent("Bitrate (kbits/sec)", "A range of bitrate of video streaming.");
public readonly GUIContent scaleFactorContent =
EditorGUIUtility.TrTextContent("Scale Resolution Down", "A factor of downscale resolution.");
}
static Styles s_Styles;
SerializedProperty m_source;
SerializedProperty m_camera;
SerializedProperty m_texture;
SerializedProperty m_frameRate;
SerializedProperty m_bitrate;
SerializedProperty m_scaleFactor;
SerializedProperty m_depth;
SerializedProperty m_antiAliasing;
SerializedProperty m_codec;
SerializedProperty m_textureSize;
SerializedProperty m_webCamDeviceIndex;
SerializedProperty m_autoRequestUserAuthorization;
static AnimBool[] m_sourceFade;
void OnEnable()
{
m_source = serializedObject.FindProperty(VideoStreamSender.SourcePropertyName);
m_camera = serializedObject.FindProperty(VideoStreamSender.CameraPropertyName);
m_texture = serializedObject.FindProperty(VideoStreamSender.TexturePropertyName);
m_webCamDeviceIndex = serializedObject.FindProperty(VideoStreamSender.WebCamDeviceIndexPropertyName);
m_codec = serializedObject.FindProperty(VideoStreamSender.CodecPropertyName);
m_textureSize = serializedObject.FindProperty(VideoStreamSender.TextureSizePropertyName);
m_frameRate = serializedObject.FindProperty(VideoStreamSender.FrameRatePropertyName);
m_bitrate = serializedObject.FindProperty(VideoStreamSender.BitratePropertyName);
m_scaleFactor = serializedObject.FindProperty(VideoStreamSender.ScaleFactorPropertyName);
m_depth = serializedObject.FindProperty(VideoStreamSender.DepthPropertyName);
m_antiAliasing = serializedObject.FindProperty(VideoStreamSender.AntiAliasingPropertyName);
m_autoRequestUserAuthorization = serializedObject.FindProperty(VideoStreamSender.AutoRequestUserAuthorizationPropertyName);
if (m_sourceFade == null)
{
m_sourceFade = new AnimBool[Enum.GetValues(typeof(VideoStreamSource)).Length];
for (int i = 0; i < m_sourceFade.Length; i++)
m_sourceFade[i] = new AnimBool(i == m_source.intValue);
}
Array.ForEach(m_sourceFade, anim => anim.valueChanged.AddListener(Repaint));
}
void OnDisable()
{
Array.ForEach(m_sourceFade, anim => anim.valueChanged.RemoveListener(Repaint));
}
public override void OnInspectorGUI()
{
if (s_Styles == null)
s_Styles = new Styles();
serializedObject.Update();
bool disableEditMediaSource = Application.isPlaying;
/// todo(kazuki): Make available to change video source parameters in runtime.
using (new EditorGUI.DisabledScope(disableEditMediaSource))
{
EditorGUILayout.PropertyField(m_source, s_Styles.sourceContent);
HandleDataSourceField();
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_codec);
}
EditorGUILayout.Space();
EditorGUILayout.PropertyField(m_frameRate, s_Styles.frameRateContent);
EditorGUILayout.PropertyField(m_bitrate, s_Styles.bitrateContent);
EditorGUILayout.PropertyField(m_scaleFactor, s_Styles.scaleFactorContent);
serializedObject.ApplyModifiedProperties();
}
private void HandleDataSourceField()
{
for (var i = 0; i < m_sourceFade.Length; i++)
m_sourceFade[i].target = m_source.intValue == i;
if (EditorGUILayout.BeginFadeGroup(m_sourceFade[(int)VideoStreamSource.Camera].faded))
{
EditorGUILayout.PropertyField(m_camera);
EditorGUILayout.PropertyField(m_depth);
EditorGUILayout.PropertyField(m_antiAliasing);
EditorGUILayout.PropertyField(m_textureSize);
}
EditorGUILayout.EndFadeGroup();
if (EditorGUILayout.BeginFadeGroup(m_sourceFade[(int)VideoStreamSource.Screen].faded))
{
EditorGUILayout.PropertyField(m_depth);
EditorGUILayout.PropertyField(m_antiAliasing);
EditorGUILayout.PropertyField(m_textureSize);
}
EditorGUILayout.EndFadeGroup();
if (EditorGUILayout.BeginFadeGroup(m_sourceFade[(int)VideoStreamSource.Texture].faded))
{
EditorGUILayout.PropertyField(m_texture);
EditorGUILayout.PropertyField(m_textureSize);
}
EditorGUILayout.EndFadeGroup();
if (EditorGUILayout.BeginFadeGroup(m_sourceFade[(int)VideoStreamSource.WebCamera].faded))
{
EditorGUILayout.PropertyField(m_webCamDeviceIndex);
EditorGUILayout.PropertyField(m_autoRequestUserAuthorization);
EditorGUILayout.PropertyField(m_textureSize);
}
EditorGUILayout.EndFadeGroup();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,138 @@
using System.Net;
using UnityEditor;
using UnityEngine;
namespace Unity.RenderStreaming.Editor
{
internal static class WebAppDownloader
{
const string URLRoot = "https://github.com/Unity-Technologies/UnityRenderStreaming";
const string LatestKnownVersion = "3.1.0-exp.8";
// TODO::fix release process of webserver runtime.
const string FileNameWebAppForMac = "webserver_mac";
const string FileNameWebAppForLinux = "webserver";
const string FileNameWebAppForWin = "webserver.exe";
//
const string PathWebAppSourceCode = "tree/release/{0}/WebApp";
const string URLWebAppDocumentation = "https://docs.unity3d.com/Packages/com.unity.renderstreaming@{0}/manual/webapp.html";
public static string GetFileName()
{
#if UNITY_EDITOR_WIN
return FileNameWebAppForWin;
#elif UNITY_EDITOR_OSX
return FileNameWebAppForMac;
#elif UNITY_EDITOR_LINUX
return FileNameWebAppForLinux;
#endif
}
public static string GetWebAppURL(string version)
{
if (version == null)
{
version = LatestKnownVersion;
}
string path = $"releases/download/{version}";
string fileName = GetFileName();
return $"{URLRoot}/{path}/{fileName}";
}
public static string GetURLDocumentation(string version)
{
var pattern = @"\d+.\d+";
var result = System.Text.RegularExpressions.Regex.Match(version, pattern);
return string.Format(URLWebAppDocumentation, result.Value);
}
public static string GetURLSourceCode(string version)
{
return System.IO.Path.Combine(URLRoot, string.Format(PathWebAppSourceCode, version));
}
public static void DownloadCurrentVersionWebApp(string dstPath, System.Action<bool> callback)
{
GetPackageVersion("com.unity.renderstreaming", (version) =>
{
DownloadWebApp(version, dstPath, callback);
});
}
public static void DownloadWebApp(string version, string dstPath, System.Action<bool> callback)
{
var url = GetWebAppURL(version);
var client = new WebClient();
var filename = System.IO.Path.GetFileName(url);
var tmpFilePath = System.IO.Path.Combine(Application.temporaryCachePath, filename);
if (string.IsNullOrEmpty(dstPath))
{
callback?.Invoke(false);
return;
}
client.DownloadFileCompleted += (sender, e) =>
{
EditorUtility.ClearProgressBar();
if (e.Error != null)
{
//Try downloading using the latest known version to work.
if (version != LatestKnownVersion)
{
DownloadWebApp(LatestKnownVersion, dstPath, callback);
}
else
{
RenderStreaming.Logger.Log(LogType.Error, $"Failed downloading web server from:{url}. Error: {e.Error}");
}
callback?.Invoke(false);
return;
}
if (!System.IO.File.Exists(tmpFilePath))
{
RenderStreaming.Logger.Log(LogType.Error, $"Download failed. url:{url}");
callback?.Invoke(false);
return;
}
dstPath = System.IO.Path.Combine(dstPath, filename);
if (System.IO.File.Exists(dstPath))
{
System.IO.File.Delete(dstPath);
}
System.IO.File.Move(tmpFilePath, dstPath);
EditorUtility.RevealInFinder(dstPath);
callback?.Invoke(true);
};
client.DownloadProgressChanged += (object sender, DownloadProgressChangedEventArgs e) =>
{
var progress = e.ProgressPercentage / 100f;
if (EditorUtility.DisplayCancelableProgressBar("Downloading", url, progress))
{
client.CancelAsync();
}
};
client.DownloadFileAsync(new System.Uri(url), tmpFilePath);
}
public static void GetPackageVersion(string packageName, System.Action<string> callback)
{
// request package list to get package version
RequestJobManager.CreateListRequest(false, true, (req) =>
{
var packageInfo = req.FindPackage(packageName);
if (null == packageInfo)
{
RenderStreaming.Logger.Log(LogType.Error, $"Not found package \"{packageName}\"");
return;
}
callback(packageInfo.version);
}, null);
}
}
}

View File

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