1220 lines
51 KiB
C#
1220 lines
51 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using System.Runtime.Serialization;
|
|
using JetBrains.Annotations;
|
|
using UnityEditor;
|
|
using UnityEditor.SceneManagement;
|
|
using UnityEditorInternal;
|
|
using UnityEngine;
|
|
using UnityEngine.Assertions;
|
|
using VRC.Udon.Common;
|
|
using VRC.Udon.Common.Interfaces;
|
|
using VRC.Udon.ProgramSources;
|
|
|
|
namespace VRC.Udon.Editor.ProgramSources
|
|
{
|
|
public class UdonProgramAsset : AbstractUdonProgramSource, ISerializationCallbackReceiver
|
|
{
|
|
protected IUdonProgram program;
|
|
|
|
[SerializeField]
|
|
protected AbstractSerializedUdonProgramAsset serializedUdonProgramAsset;
|
|
|
|
public override AbstractSerializedUdonProgramAsset SerializedProgramAsset
|
|
{
|
|
get
|
|
{
|
|
AssetDatabase.TryGetGUIDAndLocalFileIdentifier(this, out string guid, out long _);
|
|
if(serializedUdonProgramAsset != null)
|
|
{
|
|
if(serializedUdonProgramAsset.name == guid)
|
|
{
|
|
return serializedUdonProgramAsset;
|
|
}
|
|
|
|
string oldSerializedUdonProgramAssetPath = Path.Combine("Assets", "SerializedUdonPrograms", $"{serializedUdonProgramAsset.name}.asset");
|
|
AssetDatabase.DeleteAsset(oldSerializedUdonProgramAssetPath);
|
|
}
|
|
|
|
string serializedUdonProgramAssetPath = Path.Combine("Assets", "SerializedUdonPrograms", $"{guid}.asset");
|
|
|
|
serializedUdonProgramAsset = (SerializedUdonProgramAsset)AssetDatabase.LoadAssetAtPath(
|
|
Path.Combine("Assets", "SerializedUdonPrograms", $"{guid}.asset"),
|
|
typeof(SerializedUdonProgramAsset)
|
|
);
|
|
|
|
if(serializedUdonProgramAsset != null)
|
|
{
|
|
return serializedUdonProgramAsset;
|
|
}
|
|
|
|
serializedUdonProgramAsset = CreateInstance<SerializedUdonProgramAsset>();
|
|
if(!AssetDatabase.IsValidFolder(Path.Combine("Assets", "SerializedUdonPrograms")))
|
|
{
|
|
AssetDatabase.CreateFolder("Assets", "SerializedUdonPrograms");
|
|
}
|
|
|
|
AssetDatabase.CreateAsset(serializedUdonProgramAsset, serializedUdonProgramAssetPath);
|
|
AssetDatabase.SaveAssets();
|
|
|
|
RefreshProgram();
|
|
AssetDatabase.SaveAssets();
|
|
|
|
AssetDatabase.Refresh();
|
|
|
|
return serializedUdonProgramAsset;
|
|
}
|
|
}
|
|
|
|
public sealed override void RunEditorUpdate(UdonBehaviour udonBehaviour, ref bool dirty)
|
|
{
|
|
if(program == null && serializedUdonProgramAsset != null)
|
|
{
|
|
program = serializedUdonProgramAsset.RetrieveProgram();
|
|
}
|
|
|
|
if(program == null)
|
|
{
|
|
RefreshProgram();
|
|
}
|
|
|
|
DrawProgramSourceGUI(udonBehaviour, ref dirty);
|
|
|
|
if(dirty)
|
|
{
|
|
EditorUtility.SetDirty(this);
|
|
}
|
|
}
|
|
|
|
protected virtual void DrawProgramSourceGUI(UdonBehaviour udonBehaviour, ref bool dirty)
|
|
{
|
|
DrawPublicVariables(udonBehaviour, ref dirty);
|
|
DrawProgramDisassembly();
|
|
}
|
|
|
|
public sealed override void RefreshProgram()
|
|
{
|
|
if(Application.isPlaying)
|
|
{
|
|
return;
|
|
}
|
|
|
|
RefreshProgramImpl();
|
|
|
|
SerializedProgramAsset.StoreProgram(program);
|
|
EditorUtility.SetDirty(this);
|
|
}
|
|
|
|
protected virtual void RefreshProgramImpl()
|
|
{
|
|
}
|
|
|
|
[PublicAPI]
|
|
protected void DrawPublicVariables(UdonBehaviour udonBehaviour, ref bool dirty)
|
|
{
|
|
IUdonVariableTable publicVariables = null;
|
|
if(udonBehaviour != null)
|
|
{
|
|
publicVariables = udonBehaviour.publicVariables;
|
|
}
|
|
|
|
EditorGUILayout.LabelField("Public Variables", EditorStyles.boldLabel);
|
|
EditorGUI.indentLevel++;
|
|
if(program?.SymbolTable == null)
|
|
{
|
|
EditorGUILayout.LabelField("No public variables.");
|
|
EditorGUI.indentLevel--;
|
|
return;
|
|
}
|
|
|
|
IUdonSymbolTable symbolTable = program.SymbolTable;
|
|
string[] exportedSymbolNames = symbolTable.GetExportedSymbols();
|
|
|
|
// Remove non-exported public variables
|
|
if(publicVariables != null)
|
|
{
|
|
foreach(string publicVariableSymbol in publicVariables.VariableSymbols.ToArray())
|
|
{
|
|
if(!exportedSymbolNames.Contains(publicVariableSymbol))
|
|
{
|
|
publicVariables.RemoveVariable(publicVariableSymbol);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(exportedSymbolNames.Length <= 0)
|
|
{
|
|
EditorGUILayout.LabelField("No public variables.");
|
|
EditorGUI.indentLevel--;
|
|
return;
|
|
}
|
|
|
|
foreach(string exportedSymbol in exportedSymbolNames)
|
|
{
|
|
Type symbolType = symbolTable.GetSymbolType(exportedSymbol);
|
|
if(publicVariables == null)
|
|
{
|
|
DrawPublicVariableField(exportedSymbol, GetPublicVariableDefaultValue(exportedSymbol, symbolType), symbolType, ref dirty, false);
|
|
continue;
|
|
}
|
|
|
|
if(!publicVariables.TryGetVariableType(exportedSymbol, out Type declaredType) || declaredType != symbolType)
|
|
{
|
|
publicVariables.RemoveVariable(exportedSymbol);
|
|
if(!publicVariables.TryAddVariable(CreateUdonVariable(exportedSymbol, GetPublicVariableDefaultValue(exportedSymbol, declaredType), symbolType)))
|
|
{
|
|
EditorGUILayout.LabelField($"Error drawing field for symbol '{exportedSymbol}'.");
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if(!publicVariables.TryGetVariableValue(exportedSymbol, out object variableValue))
|
|
{
|
|
variableValue = GetPublicVariableDefaultValue(exportedSymbol, declaredType);
|
|
}
|
|
|
|
variableValue = DrawPublicVariableField(exportedSymbol, variableValue, symbolType, ref dirty, true);
|
|
if(!dirty)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
Undo.RecordObject(udonBehaviour, "Modify Public Variable");
|
|
|
|
if(!publicVariables.TrySetVariableValue(exportedSymbol, variableValue))
|
|
{
|
|
if(!publicVariables.TryAddVariable(CreateUdonVariable(exportedSymbol, variableValue, symbolType)))
|
|
{
|
|
Debug.LogError($"Failed to set public variable '{exportedSymbol}' value.");
|
|
}
|
|
}
|
|
|
|
EditorSceneManager.MarkSceneDirty(udonBehaviour.gameObject.scene);
|
|
|
|
if(PrefabUtility.IsPartOfPrefabInstance(udonBehaviour))
|
|
{
|
|
PrefabUtility.RecordPrefabInstancePropertyModifications(udonBehaviour);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
private static IUdonVariable CreateUdonVariable(string symbolName, object value, Type declaredType)
|
|
{
|
|
Type udonVariableType = typeof(UdonVariable<>).MakeGenericType(declaredType);
|
|
return (IUdonVariable)Activator.CreateInstance(udonVariableType, symbolName, value);
|
|
}
|
|
|
|
[PublicAPI]
|
|
protected virtual object GetPublicVariableDefaultValue(string symbol, Type type)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
[PublicAPI]
|
|
protected void DrawProgramDisassembly()
|
|
{
|
|
try
|
|
{
|
|
EditorGUILayout.LabelField("Disassembled Program", EditorStyles.boldLabel);
|
|
using(new EditorGUI.DisabledScope(true))
|
|
{
|
|
string[] disassembledProgram = UdonEditorManager.Instance.DisassembleProgram(program);
|
|
EditorGUILayout.TextArea(string.Join("\n", disassembledProgram));
|
|
}
|
|
}
|
|
catch(Exception e)
|
|
{
|
|
Debug.LogException(e);
|
|
}
|
|
}
|
|
|
|
[NonSerialized]
|
|
private readonly Dictionary<string, bool> _arrayStates = new Dictionary<string, bool>();
|
|
|
|
protected virtual object DrawPublicVariableField(string symbol, object variableValue, Type variableType, ref bool dirty, bool enabled)
|
|
{
|
|
using(new EditorGUI.DisabledScope(!enabled))
|
|
{
|
|
// ReSharper disable RedundantNameQualifier
|
|
if(!variableType.IsInstanceOfType(variableValue))
|
|
{
|
|
if(variableType.IsValueType)
|
|
{
|
|
variableValue = Activator.CreateInstance(variableType);
|
|
}
|
|
else
|
|
{
|
|
variableValue = null;
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
if(typeof(UnityEngine.Object).IsAssignableFrom(variableType))
|
|
{
|
|
UnityEngine.Object unityEngineObjectValue = (UnityEngine.Object)variableValue;
|
|
EditorGUI.BeginChangeCheck();
|
|
Rect fieldRect = EditorGUILayout.GetControlRect();
|
|
variableValue = EditorGUI.ObjectField(fieldRect, symbol, unityEngineObjectValue, variableType, true);
|
|
|
|
if(variableValue == null && (variableType == typeof(GameObject) || variableType == typeof(Transform) ||
|
|
variableType == typeof(UdonBehaviour)))
|
|
{
|
|
EditorGUI.LabelField(
|
|
fieldRect,
|
|
new GUIContent(symbol),
|
|
new GUIContent("Self (" + variableType.Name + ")", AssetPreview.GetMiniTypeThumbnail(variableType)),
|
|
EditorStyles.objectField);
|
|
}
|
|
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(string))
|
|
{
|
|
string stringValue = (string)variableValue;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.TextField(symbol, stringValue);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(string[]))
|
|
{
|
|
string[] valueArray = (string[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.TextField(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : "");
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(float))
|
|
{
|
|
float floatValue = (float?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.FloatField(symbol, floatValue);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(float[]))
|
|
{
|
|
float[] valueArray = (float[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.FloatField(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : 0);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(int))
|
|
{
|
|
int intValue = (int?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.IntField(symbol, intValue);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(int[]))
|
|
{
|
|
int[] valueArray = (int[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.IntField(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : 0);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(bool))
|
|
{
|
|
bool boolValue = (bool?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.Toggle(symbol, boolValue);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(bool[]))
|
|
{
|
|
bool[] valueArray = (bool[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.Toggle(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : false);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(UnityEngine.Vector2))
|
|
{
|
|
Vector2 vector2Value = (Vector2?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.Vector2Field(symbol, vector2Value);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(Vector2[]))
|
|
{
|
|
Vector2[] valueArray = (Vector2[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.Vector2Field(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : Vector2.zero);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(UnityEngine.Vector3))
|
|
{
|
|
Vector3 vector3Value = (Vector3?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.Vector3Field(symbol, vector3Value);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(Vector3[]))
|
|
{
|
|
Vector3[] valueArray = (Vector3[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.Vector3Field(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : Vector3.zero);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(UnityEngine.Vector4))
|
|
{
|
|
Vector4 vector4Value = (Vector4?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.Vector4Field(symbol, vector4Value);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(Vector4[]))
|
|
{
|
|
Vector4[] valueArray = (Vector4[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.Vector4Field(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : Vector4.zero);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(UnityEngine.Quaternion))
|
|
{
|
|
Quaternion quaternionValue = (Quaternion?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
Vector4 quaternionVector4 = EditorGUILayout.Vector4Field(symbol, new Vector4(quaternionValue.x, quaternionValue.y, quaternionValue.z, quaternionValue.w));
|
|
variableValue = new Quaternion(quaternionVector4.x, quaternionVector4.y, quaternionVector4.z, quaternionVector4.w);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(Quaternion[]))
|
|
{
|
|
Quaternion[] valueArray = (Quaternion[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
Vector4 vector4 = EditorGUILayout.Vector4Field(
|
|
$"{i}:",
|
|
valueArray.Length > i ? new Vector4(valueArray[i].x, valueArray[i].y, valueArray[i].z, valueArray[i].w) : Vector4.zero);
|
|
|
|
valueArray[i] = new Quaternion(vector4.x, vector4.y, vector4.z, vector4.w);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(UnityEngine.Color))
|
|
{
|
|
Color color2Value = (Color?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.ColorField(symbol, color2Value);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(Color[]))
|
|
{
|
|
Color[] valueArray = (Color[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.ColorField(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : Color.white);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(UnityEngine.Color32))
|
|
{
|
|
Color32 colorValue = (Color32?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = (Color32)EditorGUILayout.ColorField(symbol, colorValue);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(Color32[]))
|
|
{
|
|
Color32[] valueArray = (Color32[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
// Show Foldout Header
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
// Save foldout state
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.ColorField(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i] : (Color32)Color.white);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(ParticleSystem.MinMaxCurve))
|
|
{
|
|
ParticleSystem.MinMaxCurve minMaxCurve = (ParticleSystem.MinMaxCurve?)variableValue ?? default;
|
|
EditorGUI.BeginChangeCheck();
|
|
float multiplier = minMaxCurve.curveMultiplier;
|
|
AnimationCurve minCurve = minMaxCurve.curveMin;
|
|
AnimationCurve maxCurve = minMaxCurve.curveMax;
|
|
EditorGUILayout.BeginVertical();
|
|
EditorGUILayout.LabelField(symbol);
|
|
EditorGUI.indentLevel++;
|
|
multiplier = EditorGUILayout.FloatField("Multiplier", multiplier);
|
|
minCurve = EditorGUILayout.CurveField("Min Curve", minCurve);
|
|
maxCurve = EditorGUILayout.CurveField("Max Curve", maxCurve);
|
|
EditorGUI.indentLevel--;
|
|
EditorGUILayout.EndVertical();
|
|
variableValue = new ParticleSystem.MinMaxCurve(multiplier, minCurve, maxCurve);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(ParticleSystem.MinMaxCurve[]))
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.BeginVertical();
|
|
ParticleSystem.MinMaxCurve[] valueArray = (ParticleSystem.MinMaxCurve[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol, true);
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
ParticleSystem.MinMaxCurve minMaxCurve = (ParticleSystem.MinMaxCurve)valueArray[i];
|
|
float multiplier = minMaxCurve.curveMultiplier;
|
|
AnimationCurve minCurve = minMaxCurve.curveMin;
|
|
AnimationCurve maxCurve = minMaxCurve.curveMax;
|
|
EditorGUILayout.BeginVertical();
|
|
EditorGUI.indentLevel++;
|
|
multiplier = EditorGUILayout.FloatField("Multiplier", multiplier);
|
|
minCurve = EditorGUILayout.CurveField("Min Curve", minCurve);
|
|
maxCurve = EditorGUILayout.CurveField("Max Curve", maxCurve);
|
|
EditorGUI.indentLevel--;
|
|
EditorGUILayout.EndVertical();
|
|
valueArray[i] = new ParticleSystem.MinMaxCurve(multiplier, minCurve, maxCurve);
|
|
EditorGUILayout.Space();
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType.IsEnum)
|
|
{
|
|
Enum enumValue = (Enum)variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
EditorGUI.BeginChangeCheck();
|
|
variableValue = EditorGUILayout.EnumPopup(symbol, enumValue);
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
// ReSharper disable once PossibleNullReferenceException
|
|
else if(variableType.IsArray && variableType.GetElementType().IsEnum)
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.LabelField(symbol);
|
|
EditorGUILayout.BeginVertical();
|
|
Enum[] valueArray = (Enum[])variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if(_arrayStates.ContainsKey(symbol))
|
|
{
|
|
showArray = _arrayStates[symbol];
|
|
}
|
|
else
|
|
{
|
|
_arrayStates.Add(symbol, false);
|
|
}
|
|
|
|
showArray = EditorGUILayout.Foldout(showArray, symbol);
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1
|
|
);
|
|
EditorGUILayout.Space();
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if(valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.EnumPopup(
|
|
$"{i}:",
|
|
valueArray[i]);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if(variableType == typeof(Type))
|
|
{
|
|
Type typeValue = (Type)variableValue;
|
|
EditorGUILayout.LabelField(symbol, typeValue == null ? $"Type = null" : $"Type = {typeValue.Name}");
|
|
}
|
|
|
|
else if(variableType.IsArray && typeof(UnityEngine.Object).IsAssignableFrom(variableType.GetElementType()))
|
|
{
|
|
Type elementType = variableType.GetElementType();
|
|
Assert.IsNotNull(elementType);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.BeginVertical();
|
|
GUI.SetNextControlName("NodeField");
|
|
|
|
bool showArray = false;
|
|
if (_arrayStates.ContainsKey(symbol))
|
|
showArray = _arrayStates[symbol];
|
|
else
|
|
_arrayStates.Add(symbol, false);
|
|
showArray = EditorGUILayout.Foldout( showArray, symbol, true );
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
if(variableValue == null)
|
|
{
|
|
variableValue = Array.CreateInstance(elementType, 0);
|
|
}
|
|
|
|
UnityEngine.Object[] valueArray = (UnityEngine.Object[])variableValue;
|
|
|
|
if (showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray.Length > 0 ? valueArray.Length : 1);
|
|
|
|
Array.Resize(ref valueArray, newSize);
|
|
Assert.IsNotNull(valueArray);
|
|
|
|
if(valueArray.Length > 0)
|
|
{
|
|
for(int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
valueArray[i] = EditorGUILayout.ObjectField($"{i}:", valueArray.Length > i ? valueArray[i] : null, variableType.GetElementType(), true);
|
|
}
|
|
}
|
|
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
if(EditorGUI.EndChangeCheck())
|
|
{
|
|
Array destinationArray = Array.CreateInstance(elementType, valueArray.Length);
|
|
Array.Copy(valueArray, destinationArray, valueArray.Length);
|
|
|
|
variableValue = destinationArray;
|
|
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if (variableType == typeof(VRC.SDKBase.VRCUrl[]))
|
|
{
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.BeginVertical();
|
|
|
|
GUI.SetNextControlName("NodeField");
|
|
bool showArray = false;
|
|
if (_arrayStates.ContainsKey(symbol))
|
|
showArray = _arrayStates[symbol];
|
|
else
|
|
_arrayStates.Add(symbol, false);
|
|
showArray = EditorGUILayout.Foldout( showArray, symbol, true );
|
|
_arrayStates[symbol] = showArray;
|
|
|
|
VRC.SDKBase.VRCUrl[] valueArray = (VRC.SDKBase.VRCUrl[])variableValue;
|
|
|
|
if (showArray)
|
|
{
|
|
EditorGUI.indentLevel++;
|
|
EditorGUILayout.Space();
|
|
int newSize = EditorGUILayout.IntField(
|
|
"size:",
|
|
valueArray != null && valueArray.Length > 0 ? valueArray.Length : 1);
|
|
newSize = newSize >= 0 ? newSize : 0;
|
|
Array.Resize(ref valueArray, newSize);
|
|
|
|
if (valueArray != null && valueArray.Length > 0)
|
|
{
|
|
for (int i = 0; i < valueArray.Length; i++)
|
|
{
|
|
GUI.SetNextControlName("NodeField");
|
|
if (valueArray[i] == null)
|
|
valueArray[i] = new VRC.SDKBase.VRCUrl("");
|
|
|
|
valueArray[i] = new VRC.SDKBase.VRCUrl(
|
|
EditorGUILayout.TextField(
|
|
$"{i}:",
|
|
valueArray.Length > i ? valueArray[i].Get() : ""));
|
|
}
|
|
}
|
|
EditorGUI.indentLevel--;
|
|
}
|
|
|
|
EditorGUILayout.EndVertical();
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
variableValue = valueArray;
|
|
dirty = true;
|
|
}
|
|
}
|
|
else if (variableType == typeof(LayerMask))
|
|
{
|
|
LayerMask maskValue = (LayerMask)variableValue;
|
|
GUI.SetNextControlName("NodeField");
|
|
EditorGUI.BeginChangeCheck();
|
|
EditorGUILayout.LabelField(symbol);
|
|
// Using workaround from http://answers.unity.com/answers/1387522/view.html
|
|
LayerMask tempMask = EditorGUILayout.MaskField(InternalEditorUtility.LayerMaskToConcatenatedLayersMask(maskValue), InternalEditorUtility.layers);
|
|
variableValue = InternalEditorUtility.ConcatenatedLayersMaskToLayerMask(tempMask);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
dirty = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
EditorGUILayout.LabelField(symbol + " no defined editor for type of " + variableType);
|
|
}
|
|
// ReSharper restore RedundantNameQualifier
|
|
|
|
IUdonSyncMetadata sync = program.SyncMetadataTable.GetSyncMetadataFromSymbol(symbol);
|
|
if(sync != null)
|
|
{
|
|
GUILayout.Label($"sync{sync.Properties[0].InterpolationAlgorithm.ToString()}", GUILayout.Width(80));
|
|
}
|
|
}
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
return variableValue;
|
|
}
|
|
|
|
#region Serialization Methods
|
|
|
|
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
|
{
|
|
OnAfterDeserialize();
|
|
}
|
|
|
|
void ISerializationCallbackReceiver.OnBeforeSerialize()
|
|
{
|
|
OnBeforeSerialize();
|
|
}
|
|
|
|
[PublicAPI]
|
|
protected virtual void OnAfterDeserialize()
|
|
{
|
|
}
|
|
|
|
[PublicAPI]
|
|
protected virtual void OnBeforeSerialize()
|
|
{
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|