-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using UdonSharpEditor; | ||
using UnityEditor.Callbacks; | ||
using UnityEditor.Events; | ||
using UnityEngine; | ||
using UnityEngine.Events; | ||
using UnityEngine.EventSystems; | ||
using UnityEngine.UI; | ||
using VRC.Udon; | ||
using static UnityEngine.EventSystems.EventTrigger; | ||
|
||
namespace Varneon.VUdon.Components.Editor | ||
{ | ||
internal static class LayerMaskDropdownUpdater | ||
{ | ||
[PostProcessScene(-1)] // Ensure that all of the dropdowns get processed before U# saves the C# component data into UdonBehaviours | ||
private static void InitializeLayerMaskDropdowns() | ||
{ | ||
foreach(LayerMaskDropdown dropdown in UnityEngine.Object.FindObjectsOfType<LayerMaskDropdown>()) | ||
{ | ||
UpdateLayerMaskDropdown(dropdown); | ||
} | ||
} | ||
|
||
private static void UpdateLayerMaskDropdown(LayerMaskDropdown layerMaskDropdown) | ||
{ | ||
List<int> layerIndices = new List<int>(); | ||
|
||
List<string> optionNames = new List<string>() { "Nothing", "Everything" }; | ||
|
||
for (int i = 0; i < 32; i++) | ||
{ | ||
string name = LayerMask.LayerToName(i); | ||
|
||
bool isDefined = !string.IsNullOrEmpty(name); | ||
|
||
if (isDefined) | ||
{ | ||
optionNames.Add(string.Format("{0}: {1}", i, name)); | ||
|
||
layerIndices.Add(i); | ||
} | ||
} | ||
|
||
Dropdown dropdown = layerMaskDropdown.GetComponent<Dropdown>(); | ||
|
||
IEnumerable<FieldInfo> fields = typeof(LayerMaskDropdown).GetRuntimeFields(); | ||
|
||
FieldInfo layerCountField = fields.FirstOrDefault(f => f.Name == "projectLayerCount"); | ||
|
||
FieldInfo layersField = fields.FirstOrDefault(f => f.Name == "layers"); | ||
|
||
EventTrigger trigger = layerMaskDropdown.GetComponent<EventTrigger>(); | ||
|
||
layerCountField.SetValue(layerMaskDropdown, optionNames.Count - 2); | ||
|
||
layersField.SetValue(layerMaskDropdown, layerIndices.ToArray()); | ||
|
||
dropdown.options = optionNames.Select(l => new Dropdown.OptionData(l)).ToList(); | ||
|
||
UdonBehaviour ub = UdonSharpEditorUtility.GetBackingUdonBehaviour(layerMaskDropdown); | ||
|
||
MethodInfo sendCustomEventInfo = UnityEventBase.GetValidMethodInfo(ub, nameof(UdonBehaviour.SendCustomEvent), new[] { typeof(string) }); | ||
|
||
UnityAction<string> sendCustomEventDelegate = Delegate.CreateDelegate(typeof(UnityAction<string>), ub, sendCustomEventInfo, false) as UnityAction<string>; | ||
|
||
UnityEventTools.AddStringPersistentListener(dropdown.onValueChanged, sendCustomEventDelegate, "OnValueChanged"); | ||
|
||
Entry pointerClickEntry = new Entry | ||
{ | ||
eventID = EventTriggerType.PointerClick, | ||
callback = new TriggerEvent() | ||
}; | ||
UnityEventTools.AddStringPersistentListener(pointerClickEntry.callback, sendCustomEventDelegate, "OnClick"); | ||
|
||
Entry selectEntry = new Entry | ||
{ | ||
eventID = EventTriggerType.Select, | ||
callback = new TriggerEvent() | ||
}; | ||
UnityEventTools.AddStringPersistentListener(selectEntry.callback, sendCustomEventDelegate, "OnSelect"); | ||
|
||
trigger.triggers.Add(pointerClickEntry); | ||
trigger.triggers.Add(selectEntry); | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
{ | ||
"name": "Varneon.V-Udon.Components.Editor", | ||
"references": [ | ||
"Varneon.V-Udon.Components.Runtime", | ||
"UdonSharp.Runtime", | ||
"VRC.Udon", | ||
"UdonSharp.Editor" | ||
], | ||
"includePlatforms": [ | ||
"Editor" | ||
], | ||
"excludePlatforms": [], | ||
"allowUnsafeCode": false, | ||
"overrideReferences": false, | ||
"precompiledReferences": [], | ||
"autoReferenced": true, | ||
"defineConstraints": [ | ||
"UDONSHARP" | ||
], | ||
"versionDefines": [], | ||
"noEngineReferences": false | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
using UdonSharp; | ||
using UnityEngine; | ||
using UnityEngine.EventSystems; | ||
using UnityEngine.UI; | ||
using VRC.Udon; | ||
|
||
namespace Varneon.VUdon.Components | ||
{ | ||
[RequireComponent(typeof(Dropdown))] | ||
[RequireComponent(typeof(EventTrigger))] | ||
[UdonBehaviourSyncMode(BehaviourSyncMode.None)] | ||
public class LayerMaskDropdown : UdonSharpBehaviour | ||
{ | ||
[SerializeField, HideInInspector] | ||
private int projectLayerCount; | ||
|
||
[SerializeField, HideInInspector] | ||
private int[] layers; | ||
|
||
[SerializeField] | ||
private UdonBehaviour target; | ||
|
||
[SerializeField] | ||
private string variable; | ||
|
||
private LayerMask mask; | ||
|
||
private Dropdown cullingMaskDropdown; | ||
|
||
private int maskInt; | ||
|
||
private Toggle[] cullingMaskToggles; | ||
|
||
private Text dropdownValueLabel; | ||
|
||
private bool isOpen; | ||
|
||
private void Start() | ||
{ | ||
cullingMaskDropdown = GetComponent<Dropdown>(); | ||
|
||
dropdownValueLabel = cullingMaskDropdown.captionText; | ||
|
||
maskInt = mask; | ||
|
||
SetTargetVariable(); | ||
|
||
CheckMixedLayers(); | ||
} | ||
|
||
private void SetTargetVariable() | ||
{ | ||
if(target != null && !string.IsNullOrWhiteSpace(variable)) | ||
|
||
target.SetProgramVariable(variable, mask); | ||
} | ||
|
||
private void OpenCullingMaskMenu() | ||
{ | ||
isOpen = true; | ||
|
||
cullingMaskToggles = cullingMaskDropdown.GetComponentsInChildren<Toggle>(true); | ||
|
||
for (int i = 0; i < projectLayerCount; i++) | ||
{ | ||
cullingMaskToggles[i + 4].SetIsOnWithoutNotify((maskInt & (1 << layers[i])) != 0); | ||
} | ||
} | ||
|
||
public void OnClick() | ||
{ | ||
OpenCullingMaskMenu(); | ||
} | ||
|
||
public void OnSelect() | ||
{ | ||
if (isOpen) { UpdateCullingMask(); } | ||
} | ||
|
||
public void OnValueChanged() | ||
{ | ||
UpdateCullingMask(); | ||
} | ||
|
||
private void UpdateCullingMask() | ||
{ | ||
int selectedLayerOption = cullingMaskDropdown.value; | ||
|
||
switch (selectedLayerOption) | ||
{ | ||
case 0: // Nothing | ||
maskInt = 0; | ||
break; | ||
case 1: // Everything | ||
maskInt = -1; | ||
break; | ||
default: | ||
int mask = 1 << layers[selectedLayerOption - 2]; // Create bitmask of the layer that was clicked | ||
|
||
if (isOpen) | ||
{ | ||
if ((maskInt & mask) != 0) // If same bit is set on both the culling mask and the selection mask | ||
{ | ||
maskInt &= ~mask; // Reset the bit | ||
} | ||
else | ||
{ | ||
maskInt |= mask; // Set the bit | ||
} | ||
} | ||
|
||
CheckMixedLayers(); | ||
break; | ||
} | ||
|
||
mask = maskInt; | ||
|
||
SetTargetVariable(); | ||
|
||
isOpen = false; | ||
} | ||
|
||
private void CheckMixedLayers() | ||
{ | ||
int layerCount = 0; | ||
|
||
int optionIndex = 0; | ||
|
||
for (int i = 0; i < projectLayerCount; i++) | ||
{ | ||
if ((maskInt & (1 << layers[i])) != 0) | ||
{ | ||
optionIndex = i; | ||
|
||
layerCount += 1; | ||
} | ||
} | ||
|
||
if (layerCount == projectLayerCount) | ||
{ | ||
maskInt = -1; | ||
|
||
cullingMaskDropdown.SetValueWithoutNotify(1); | ||
} | ||
else if (layerCount > 1) // If multiple layers are selected, set the preview label as "Mixed..." | ||
{ | ||
dropdownValueLabel.text = "Mixed..."; | ||
} | ||
else if (layerCount == 1) // If only one layer is selected, override the dropdown with the remaining layer | ||
{ | ||
cullingMaskDropdown.SetValueWithoutNotify(optionIndex + 2); | ||
} | ||
else if (layerCount == 0) // If no layers have been selected, override the dropdown to Nothing / 0 | ||
{ | ||
cullingMaskDropdown.SetValueWithoutNotify(0); | ||
} | ||
} | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.