multiple xr toolkit package
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VRC_TriggerEditor.cs 80KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502
  1. #if UNITY_EDITOR
  2. using UnityEngine;
  3. using UnityEngine.UI;
  4. using UnityEditor;
  5. using UnityEditorInternal;
  6. using System.Linq;
  7. using System.Collections.Generic;
  8. using System.Reflection;
  9. using System;
  10. namespace VRCSDK2
  11. {
  12. [CustomPropertyDrawer(typeof(VRCSDK2.VRC_Trigger.CustomTriggerTarget))]
  13. public class CustomTriggerTargetDrawer : PropertyDrawer
  14. {
  15. public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
  16. {
  17. if (Application.isPlaying)
  18. {
  19. EditorGUI.HelpBox(rect, "Trigger Editor disabled while application is running.", MessageType.Info);
  20. return;
  21. }
  22. if (property == null)
  23. return;
  24. SerializedProperty objectProperty = property.FindPropertyRelative("TriggerObject");
  25. SerializedProperty nameProperty = property.FindPropertyRelative("CustomName");
  26. EditorGUI.BeginProperty(rect, label, property);
  27. rect = EditorGUI.PrefixLabel(rect, GUIUtility.GetControlID(FocusType.Passive), label);
  28. Rect objectRect = new Rect(rect.x, rect.y, rect.width / 2 - 5, rect.height);
  29. Rect nameRect = new Rect(rect.x + rect.width / 2, rect.y, rect.width / 2, rect.height);
  30. VRC_Trigger current = null;
  31. if (objectProperty.objectReferenceValue != null)
  32. current = (objectProperty.objectReferenceValue as GameObject).GetComponent<VRC_Trigger>();
  33. current = EditorGUI.ObjectField(objectRect, current, typeof(VRC_Trigger), true) as VRC_Trigger;
  34. objectProperty.objectReferenceValue = current == null ? null : current.gameObject;
  35. VRC_EditorTools.CustomTriggerPopup(nameRect, objectProperty, nameProperty);
  36. EditorGUI.EndProperty();
  37. }
  38. }
  39. [CustomEditor(typeof(VRCSDK2.VRC_Trigger)), CanEditMultipleObjects]
  40. public class VRC_TriggerEditor : Editor
  41. {
  42. private List<VRC_Trigger.TriggerType> ActiveTypes
  43. {
  44. get
  45. {
  46. List<VRC_Trigger.TriggerType> activeTypes = new List<VRC_Trigger.TriggerType>();
  47. SerializedProperty triggers = triggersProperty.Copy();
  48. int triggersLength = triggers.arraySize;
  49. for (int idx = 0; idx < triggersLength; ++idx)
  50. {
  51. VRC_Trigger.TriggerType triggerType = (VRC_Trigger.TriggerType)triggers.GetArrayElementAtIndex(idx).FindPropertyRelative("TriggerType").intValue;
  52. activeTypes.Add(triggerType);
  53. }
  54. return activeTypes;
  55. }
  56. }
  57. #pragma warning disable CS0618 // Type or member is obsolete
  58. private static List<VRC_Trigger.TriggerType> hiddenTriggerTypes = new List<VRC_Trigger.TriggerType> { VRC_Trigger.TriggerType.OnDataStorageAdd, VRC_Trigger.TriggerType.OnDataStorageRemove };
  59. private static List<VRC_EventHandler.VrcEventType> hiddenEventTypes = new List<VRC_EventHandler.VrcEventType> { VRC_EventHandler.VrcEventType.MeshVisibility, VRC_EventHandler.VrcEventType.SendMessage, VRC_EventHandler.VrcEventType.RunConsoleCommand };
  60. private static List<VRC_EventHandler.VrcBroadcastType> unbufferedBroadcastTypes = new List<VRC_EventHandler.VrcBroadcastType> { VRC_EventHandler.VrcBroadcastType.AlwaysUnbuffered, VRC_EventHandler.VrcBroadcastType.MasterUnbuffered, VRC_EventHandler.VrcBroadcastType.OwnerUnbuffered, VRC_EventHandler.VrcBroadcastType.Local };
  61. private static List<VRC_EventHandler.VrcBroadcastType> bufferOneBroadcastTypes = new List<VRC_EventHandler.VrcBroadcastType> { VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne, VRC_EventHandler.VrcBroadcastType.MasterBufferOne, VRC_EventHandler.VrcBroadcastType.OwnerBufferOne };
  62. private static List<VRC_EventHandler.VrcBroadcastType> simpleBroadcastTypes = new List<VRC_EventHandler.VrcBroadcastType> { VRC_EventHandler.VrcBroadcastType.AlwaysUnbuffered, VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne, VRC_EventHandler.VrcBroadcastType.OwnerBufferOne, VRC_EventHandler.VrcBroadcastType.OwnerUnbuffered };
  63. private static List<VRC_EventHandler.VrcBroadcastType> hiddenBroadcastTypes = new List<VRC_EventHandler.VrcBroadcastType> { };
  64. #pragma warning restore CS0618 // Type or member is obsolete
  65. private ReorderableList[] eventLists = new ReorderableList[0];
  66. private ReorderableList[] relayLists = new ReorderableList[0];
  67. private ReorderableList[] objectLists = new ReorderableList[0];
  68. private bool[] visible = new bool[0];
  69. private SerializedProperty triggersProperty;
  70. private SerializedProperty proximityProperty;
  71. private SerializedProperty interactTextProperty;
  72. private SerializedProperty advancedProperty;
  73. private SerializedProperty ownershipProperty;
  74. private SerializedProperty helpProperty;
  75. private Dictionary<string, object[]> rpcByteCache = new Dictionary<string, object[]>();
  76. private VRC_Trigger.TriggerType addTriggerSelectedType = VRC_Trigger.TriggerType.Custom;
  77. private void OnEnable()
  78. {
  79. rpcByteCache.Clear();
  80. }
  81. public override void OnInspectorGUI()
  82. {
  83. #pragma warning disable CS0618 // Type or member is obsolete
  84. bool showedOldWarning = false;
  85. foreach (VRC_Trigger t in targets.Cast<VRC_Trigger>().Where(tr => tr != null))
  86. {
  87. if (!showedOldWarning && (t.GetComponent<VRCSDK2.VRC_UseEvents>() != null || t.GetComponent<VRCSDK2.VRC_KeyEvents>() != null || t.GetComponent<VRCSDK2.VRC_TriggerColliderEventTrigger>() != null || t.GetComponent<VRCSDK2.VRC_TimedEvents>() != null))
  88. {
  89. EditorGUILayout.HelpBox("Do not use VRC_Trigger in combination with deprecated event components.", MessageType.Error);
  90. showedOldWarning = true;
  91. }
  92. VRCSDK2.VRC_EventHandler handler = t.GetComponent<VRCSDK2.VRC_EventHandler>();
  93. if (handler != null)
  94. handler.Events = new List<VRC_EventHandler.VrcEvent>();
  95. }
  96. #pragma warning restore CS0618 // Type or member is obsolete
  97. triggersProperty = serializedObject.FindProperty("Triggers");
  98. proximityProperty = serializedObject.FindProperty("proximity");
  99. interactTextProperty = serializedObject.FindProperty("interactText");
  100. advancedProperty = serializedObject.FindProperty("UsesAdvancedOptions");
  101. ownershipProperty = serializedObject.FindProperty("TakesOwnershipIfNecessary");
  102. helpProperty = serializedObject.FindProperty("ShowHelp");
  103. serializedObject.Update();
  104. SerializedProperty triggers = triggersProperty.Copy();
  105. int triggersLength = triggers.arraySize;
  106. if (eventLists.Length != triggersLength)
  107. eventLists = new ReorderableList[triggersLength];
  108. if (relayLists.Length != triggersLength)
  109. relayLists = new ReorderableList[triggersLength];
  110. if (objectLists.Length != triggersLength)
  111. objectLists = new ReorderableList[triggersLength];
  112. if (visible.Length != triggersLength)
  113. {
  114. bool[] newVisible = new bool[triggersLength];
  115. for (int idx = 0; idx < visible.Length && idx < newVisible.Length; ++idx)
  116. newVisible[idx] = visible[idx];
  117. for (int idx = visible.Length; idx < newVisible.Length && idx < newVisible.Length; ++idx)
  118. newVisible[idx] = true;
  119. visible = newVisible;
  120. }
  121. EditorGUILayout.BeginVertical(GUILayout.MaxWidth(EditorGUIUtility.currentViewWidth - 30));
  122. EditorGUILayout.PropertyField(advancedProperty, new GUIContent("Advanced Mode"));
  123. EditorGUILayout.PropertyField(ownershipProperty, new GUIContent("Take Ownership of Action Targets"));
  124. EditorGUILayout.PropertyField(helpProperty, new GUIContent("Show Help"));
  125. EditorGUILayout.Space();
  126. RenderTriggers();
  127. EditorGUILayout.EndVertical();
  128. serializedObject.ApplyModifiedProperties();
  129. }
  130. private void RenderHelpBox(string message, MessageType messageType)
  131. {
  132. if (helpProperty.boolValue || messageType == MessageType.Error)
  133. EditorGUILayout.HelpBox(message, messageType);
  134. }
  135. private void RenderTriggers()
  136. {
  137. GUIStyle triggerStyle = new GUIStyle(EditorStyles.helpBox);
  138. SerializedProperty triggers = triggersProperty.Copy();
  139. int triggersLength = triggers.arraySize;
  140. List<int> to_remove = new List<int>();
  141. for (int idx = 0; idx < triggersLength; ++idx)
  142. {
  143. SerializedProperty triggerProperty = triggers.GetArrayElementAtIndex(idx);
  144. SerializedProperty broadcastProperty = triggerProperty.FindPropertyRelative("BroadcastType");
  145. EditorGUILayout.BeginVertical(triggerStyle);
  146. if (RenderTriggerHeader(triggerProperty, ref visible[idx]))
  147. {
  148. to_remove.Add(idx);
  149. EditorGUILayout.EndVertical();
  150. continue;
  151. }
  152. if (!visible[idx])
  153. {
  154. EditorGUILayout.EndVertical();
  155. continue;
  156. }
  157. if (!unbufferedBroadcastTypes.Contains((VRC_EventHandler.VrcBroadcastType)broadcastProperty.intValue) &&
  158. !bufferOneBroadcastTypes.Contains((VRC_EventHandler.VrcBroadcastType)broadcastProperty.intValue) &&
  159. ActiveEvents(triggerProperty).Any(e => e == VRC_EventHandler.VrcEventType.SendRPC))
  160. RenderHelpBox("Consider using unbuffered broadcasts with RPCs.", MessageType.Error);
  161. EditorGUILayout.Separator();
  162. RenderTriggerEditor(triggerProperty, idx);
  163. if (eventLists.Length == triggersLength)
  164. {
  165. EditorGUILayout.Separator();
  166. if (triggerProperty.FindPropertyRelative("TriggerType").intValue != (int)VRC_Trigger.TriggerType.Relay)
  167. {
  168. RenderTriggerEventsEditor(triggerProperty, idx);
  169. EditorGUILayout.Separator();
  170. }
  171. }
  172. EditorGUILayout.EndVertical();
  173. }
  174. foreach (int idx in ((IEnumerable<int>)to_remove).Reverse())
  175. triggersProperty.Copy().DeleteArrayElementAtIndex(idx);
  176. RenderAddTrigger();
  177. }
  178. private void RenderTriggerEditor(SerializedProperty triggerProperty, int idx)
  179. {
  180. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("AfterSeconds"), new GUIContent("Delay in Seconds"));
  181. VRC_Trigger.TriggerType triggerType = (VRC_Trigger.TriggerType)triggerProperty.FindPropertyRelative("TriggerType").intValue;
  182. switch (triggerType)
  183. {
  184. case VRC_Trigger.TriggerType.Custom:
  185. RenderCustom(triggerProperty);
  186. break;
  187. case VRC_Trigger.TriggerType.Relay:
  188. RenderRelay(triggerProperty, idx);
  189. break;
  190. case VRC_Trigger.TriggerType.OnEnterTrigger:
  191. case VRC_Trigger.TriggerType.OnExitTrigger:
  192. case VRC_Trigger.TriggerType.OnEnterCollider:
  193. case VRC_Trigger.TriggerType.OnExitCollider:
  194. RenderCollider(triggerProperty);
  195. break;
  196. case VRC_Trigger.TriggerType.OnKeyDown:
  197. case VRC_Trigger.TriggerType.OnKeyUp:
  198. RenderKey(triggerProperty);
  199. break;
  200. case VRC_Trigger.TriggerType.OnTimer:
  201. RenderTimer(triggerProperty);
  202. break;
  203. case VRC_Trigger.TriggerType.OnDataStorageAdd:
  204. case VRC_Trigger.TriggerType.OnDataStorageChange:
  205. case VRC_Trigger.TriggerType.OnDataStorageRemove:
  206. RenderDataStorage(triggerProperty);
  207. break;
  208. case VRC_Trigger.TriggerType.OnParticleCollision:
  209. //RenderHelpBox("Triggers for each particle in attached particle system that collides with something.", MessageType.Info);
  210. RenderEmpty(triggerProperty);
  211. break;
  212. default:
  213. if (VRC_Trigger.TypeCollections.InteractiveTypes.Contains(triggerType) || VRC_Trigger.TypeCollections.PickupTypes.Contains(triggerType))
  214. RenderInteractableEditor();
  215. else
  216. RenderEmpty(triggerProperty);
  217. break;
  218. }
  219. }
  220. private List<VRC_EventHandler.VrcEventType> ActiveEvents(SerializedProperty triggerProperty)
  221. {
  222. List<VRC_EventHandler.VrcEventType> activeTypes = new List<VRC_EventHandler.VrcEventType>();
  223. SerializedProperty events = triggerProperty.FindPropertyRelative("Events").Copy();
  224. int eventsLength = events.arraySize;
  225. for (int idx = 0; idx < eventsLength; ++idx)
  226. {
  227. VRC_EventHandler.VrcEventType eventType = (VRC_EventHandler.VrcEventType)events.GetArrayElementAtIndex(idx).FindPropertyRelative("EventType").intValue;
  228. activeTypes.Add(eventType);
  229. }
  230. return activeTypes;
  231. }
  232. private void RenderAddTrigger()
  233. {
  234. Rect rect = EditorGUILayout.BeginHorizontal(GUILayout.Height(15f));
  235. EditorGUILayout.Space();
  236. Rect selectedRect = new Rect(rect.x, rect.y, rect.width / 4 * 3 - 5, rect.height);
  237. Rect addRect = new Rect(selectedRect.x + selectedRect.width + 5, rect.y, rect.width / 4, rect.height);
  238. bool showStationTypes = serializedObject.targetObjects.Any(o => (o as VRC_Trigger).GetComponent<VRCSDK2.VRC_Station>() != null);
  239. System.Func<VRC_Trigger.TriggerType, bool> predicate =
  240. v => hiddenTriggerTypes.Contains(v) == false && (showStationTypes || (v != VRC_Trigger.TriggerType.OnStationEntered && v != VRC_Trigger.TriggerType.OnStationExited));
  241. addTriggerSelectedType = VRC_EditorTools.FilteredEnumPopup(selectedRect, addTriggerSelectedType, predicate);
  242. if (GUI.Button(addRect, "Add"))
  243. {
  244. SerializedProperty triggersAry = triggersProperty;
  245. // hacks
  246. triggersAry.Next(true);
  247. triggersAry.Next(true);
  248. int triggersLength = triggersAry.intValue;
  249. triggersAry.intValue = triggersLength + 1;
  250. triggersAry.Next(true);
  251. for (int idx = 0; idx < triggersLength; ++idx)
  252. triggersAry.Next(false);
  253. triggersAry.FindPropertyRelative("TriggerType").intValue = (int)addTriggerSelectedType;
  254. triggersAry.FindPropertyRelative("BroadcastType").intValue = (int)VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne;
  255. triggersAry.FindPropertyRelative("TriggerIndividuals").boolValue = true;
  256. triggersAry.FindPropertyRelative("Layers").intValue = LayerMask.GetMask("Default");
  257. }
  258. EditorGUILayout.EndHorizontal();
  259. }
  260. private bool RenderTriggerHeader(SerializedProperty triggerProperty, ref bool expand)
  261. {
  262. bool delete = false;
  263. if (!delete)
  264. {
  265. VRC_EventHandler.VrcBroadcastType? broadcast = null;
  266. Rect rect = EditorGUILayout.BeginHorizontal(GUILayout.Height(15f));
  267. EditorGUILayout.Space();
  268. int baseWidth = (int)((rect.width - 40) / 4);
  269. Rect foldoutRect = new Rect(rect.x + 10, rect.y, 20, rect.height);
  270. Rect typeRect = new Rect(rect.x + 20, rect.y, baseWidth, rect.height);
  271. Rect broadcastRect = new Rect(rect.x + 25 + baseWidth, rect.y, baseWidth, rect.height);
  272. Rect randomRect = new Rect(rect.x + 30 + baseWidth * 2, rect.y, baseWidth, rect.height);
  273. Rect removeRect = new Rect(rect.x + 35 + baseWidth * 3, rect.y, baseWidth, rect.height);
  274. expand = EditorGUI.Foldout(foldoutRect, expand, GUIContent.none);
  275. SerializedProperty triggerTypeProperty = triggerProperty.FindPropertyRelative("TriggerType");
  276. VRC_Trigger.TriggerType currentType = (VRC_Trigger.TriggerType)triggerTypeProperty.intValue;
  277. SerializedProperty nameProperty = triggerProperty.FindPropertyRelative("Name");
  278. if (string.IsNullOrEmpty(nameProperty.stringValue))
  279. nameProperty.stringValue = "Unnamed";
  280. bool showStationTypes = serializedObject.targetObjects.Any(o => (o as VRC_Trigger).GetComponent<VRCSDK2.VRC_Station>() != null);
  281. System.Func<string, string> rename = s => s == "Custom" ? s + " (" + nameProperty.stringValue + ")" : s;
  282. System.Func<VRC_Trigger.TriggerType, bool> predicate =
  283. v => hiddenTriggerTypes.Contains(v) == false && (showStationTypes || (v != VRC_Trigger.TriggerType.OnStationEntered && v != VRC_Trigger.TriggerType.OnStationExited));
  284. triggerTypeProperty.intValue = (int)VRC_EditorTools.FilteredEnumPopup(typeRect, currentType, predicate, rename);
  285. currentType = (VRC_Trigger.TriggerType)triggerTypeProperty.intValue;
  286. SerializedProperty broadcastTypeProperty = triggerProperty.FindPropertyRelative("BroadcastType");
  287. List<VRC_EventHandler.VrcEventType> activeEvents = ActiveEvents(triggerProperty);
  288. if ((VRC_Trigger.TriggerType)triggerTypeProperty.intValue == VRC_Trigger.TriggerType.Relay || activeEvents.Contains(VRC_EventHandler.VrcEventType.SpawnObject))
  289. {
  290. broadcast = VRC_EventHandler.VrcBroadcastType.Always;
  291. broadcastTypeProperty.intValue = (int)broadcast;
  292. }
  293. else
  294. {
  295. VRC_EditorTools.FilteredEnumPopup<VRC_EventHandler.VrcBroadcastType>(broadcastRect, broadcastTypeProperty, b => !hiddenBroadcastTypes.Contains(b) && (advancedProperty.boolValue || simpleBroadcastTypes.Contains(b)));
  296. broadcast = (VRC_EventHandler.VrcBroadcastType)broadcastTypeProperty.intValue;
  297. }
  298. SerializedProperty probabilitiesProperty = triggerProperty.FindPropertyRelative("Probabilities");
  299. SerializedProperty probabilityLockProperty = triggerProperty.FindPropertyRelative("ProbabilityLock");
  300. SerializedProperty eventsProperty = triggerProperty.FindPropertyRelative("Events");
  301. if (advancedProperty.boolValue && GUI.Toggle(randomRect, probabilitiesProperty.arraySize > 0, new GUIContent(" Randomize")))
  302. probabilityLockProperty.arraySize = probabilitiesProperty.arraySize = eventsProperty.arraySize;
  303. else
  304. probabilityLockProperty.arraySize = probabilitiesProperty.arraySize = 0;
  305. if (GUI.Button(removeRect, "Remove"))
  306. delete = true;
  307. EditorGUILayout.EndHorizontal();
  308. if (broadcast.HasValue && expand)
  309. {
  310. string message = null;
  311. switch (broadcast.Value)
  312. {
  313. case VRC_EventHandler.VrcBroadcastType.Always:
  314. message = "All are able to activate the trigger for everyone, and late-joiners will also trigger it.";
  315. break;
  316. case VRC_EventHandler.VrcBroadcastType.AlwaysUnbuffered:
  317. message = "All are able to activate the trigger for everyone, but late-joiners will not trigger it.";
  318. break;
  319. case VRC_EventHandler.VrcBroadcastType.Local:
  320. message = "All are able to activate the trigger for themselves only.";
  321. break;
  322. case VRC_EventHandler.VrcBroadcastType.Master:
  323. message = "Only the Master is able to activate the trigger for everyone, and late-joiners will also trigger it.";
  324. break;
  325. case VRC_EventHandler.VrcBroadcastType.MasterUnbuffered:
  326. message = "Only the Master is able to activate the trigger for everyone, but late-joiners will not trigger it.";
  327. break;
  328. case VRC_EventHandler.VrcBroadcastType.Owner:
  329. message = "Only the Owner is able to activate the trigger for everyone, and late-joiners will also trigger it.";
  330. break;
  331. case VRC_EventHandler.VrcBroadcastType.OwnerUnbuffered:
  332. message = "Only the Owner is able to activate the trigger for everyone, but late-joiners will not trigger it.";
  333. break;
  334. case VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne:
  335. message = "All are able to activate the trigger for everyone, and late-joiners will trigger the most recent one.";
  336. break;
  337. case VRC_EventHandler.VrcBroadcastType.MasterBufferOne:
  338. message = "Only the Master is able to activate the trigger for everyone, and late-joiners will trigger the most recent one.";
  339. break;
  340. case VRC_EventHandler.VrcBroadcastType.OwnerBufferOne:
  341. message = "Only the Owner is able to activate the trigger for everyone, and late-joiners will trigger the most recent one.";
  342. break;
  343. }
  344. if (message != null)
  345. RenderHelpBox(message, MessageType.Info);
  346. }
  347. }
  348. return delete;
  349. }
  350. private void RenderInteractableEditor()
  351. {
  352. EditorGUILayout.PropertyField(interactTextProperty, new GUIContent("Interaction Text"));
  353. proximityProperty.floatValue = EditorGUILayout.Slider("Proximity", proximityProperty.floatValue, 0f, 100f);
  354. }
  355. private void RenderTriggerEventsEditor(SerializedProperty triggerProperty, int idx)
  356. {
  357. if (eventLists[idx] == null)
  358. {
  359. ReorderableList newList = new ReorderableList(serializedObject, triggerProperty.FindPropertyRelative("Events"), true, true, true, true);
  360. newList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, "Actions");
  361. newList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
  362. {
  363. SerializedProperty eventsListProperty = triggerProperty.FindPropertyRelative("Events");
  364. SerializedProperty probabilitiesProperty = triggerProperty.FindPropertyRelative("Probabilities");
  365. SerializedProperty probabilityLockProperty = triggerProperty.FindPropertyRelative("ProbabilityLock");
  366. SerializedProperty shadowListProperty = triggerProperty.FindPropertyRelative("DataStorageShadowValues");
  367. if (shadowListProperty != null && shadowListProperty.arraySize != eventsListProperty.arraySize)
  368. shadowListProperty.arraySize = eventsListProperty.arraySize;
  369. SerializedProperty shadowProperty = shadowListProperty == null ? null : shadowListProperty.GetArrayElementAtIndex(index);
  370. SerializedProperty eventProperty = eventsListProperty.GetArrayElementAtIndex(index);
  371. SerializedProperty eventTypeProperty = eventProperty.FindPropertyRelative("EventType");
  372. SerializedProperty parameterStringProperty = eventProperty.FindPropertyRelative("ParameterString");
  373. string label = ((VRC_EventHandler.VrcEventType)eventTypeProperty.intValue).ToString();
  374. if (!string.IsNullOrEmpty(parameterStringProperty.stringValue))
  375. label += " (" + parameterStringProperty.stringValue + ")";
  376. if (probabilitiesProperty.arraySize == 0 || !advancedProperty.boolValue)
  377. EditorGUI.LabelField(rect, label);
  378. else
  379. {
  380. Rect labelRect = new Rect(rect.x, rect.y, rect.width / 2, rect.height);
  381. Rect sliderLockRect = new Rect(rect.x + rect.width / 2, rect.y, 30, rect.height);
  382. Rect sliderRect = new Rect(rect.x + rect.width / 2 + 30, rect.y, rect.width / 2 - 30, rect.height);
  383. EditorGUI.LabelField(labelRect, label);
  384. probabilityLockProperty.GetArrayElementAtIndex(index).boolValue = GUI.Toggle(sliderLockRect, probabilityLockProperty.GetArrayElementAtIndex(index).boolValue, new GUIContent());
  385. probabilitiesProperty.GetArrayElementAtIndex(index).floatValue = EditorGUI.Slider(sliderRect, new GUIContent(), probabilitiesProperty.GetArrayElementAtIndex(index).floatValue, 0f, 1f);
  386. bool allLocked = true;
  387. for (int pIdx = 0; pIdx < probabilitiesProperty.arraySize; ++pIdx)
  388. allLocked = allLocked && probabilityLockProperty.GetArrayElementAtIndex(pIdx).boolValue;
  389. if (allLocked)
  390. for (int pIdx = 0; pIdx < probabilitiesProperty.arraySize; ++pIdx)
  391. if (pIdx != index)
  392. probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue = probabilitiesProperty.GetArrayElementAtIndex(index).floatValue;
  393. // Squish 'em down
  394. float probabilitySum = 1f;
  395. const int MAX_SCALE_PROBABILITIES_LOOP_ITERATIONS = 8;
  396. const int PROBABILITY_VALUE_DECIMAL_PLACES = 3;
  397. int loopIterations = 0;
  398. do
  399. {
  400. if (probabilitySum > 1f)
  401. {
  402. float fixRatio = 1f / probabilitySum;
  403. int countChanged = 0;
  404. for (int pIdx = 0; pIdx < probabilitiesProperty.arraySize; ++pIdx)
  405. {
  406. if (allLocked)
  407. {
  408. countChanged++;
  409. probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue *= fixRatio;
  410. }
  411. else
  412. {
  413. if (pIdx == index || probabilityLockProperty.GetArrayElementAtIndex(pIdx).boolValue || probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue == 0f)
  414. continue;
  415. countChanged++;
  416. probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue *= fixRatio;
  417. }
  418. }
  419. if (countChanged == 0)
  420. probabilitiesProperty.GetArrayElementAtIndex(index).floatValue -= probabilitySum - 1f;
  421. probabilitiesProperty.GetArrayElementAtIndex(index).floatValue = (float)Math.Round(probabilitiesProperty.GetArrayElementAtIndex(index).floatValue, PROBABILITY_VALUE_DECIMAL_PLACES);
  422. }
  423. probabilitySum = 0f;
  424. for (int pIdx = 0; pIdx < probabilitiesProperty.arraySize; ++pIdx)
  425. probabilitySum += probabilitiesProperty.GetArrayElementAtIndex(pIdx).floatValue;
  426. loopIterations++;
  427. } while ((probabilitySum > 1f) && (loopIterations<MAX_SCALE_PROBABILITIES_LOOP_ITERATIONS));
  428. }
  429. if (isFocused)
  430. objectLists[idx] = null;
  431. if (isActive)
  432. {
  433. EditorGUILayout.Space();
  434. RenderEventEditor(shadowProperty, triggerProperty, eventProperty, idx);
  435. }
  436. };
  437. newList.onAddDropdownCallback = (Rect buttonRect, ReorderableList list) =>
  438. {
  439. GenericMenu menu = new GenericMenu();
  440. SerializedProperty eventsList = triggerProperty.FindPropertyRelative("Events");
  441. foreach (VRC_EventHandler.VrcEventType type in System.Enum.GetValues(typeof(VRC_EventHandler.VrcEventType)).Cast<VRC_EventHandler.VrcEventType>().Where(v => !hiddenEventTypes.Contains(v) && !(v == VRC_EventHandler.VrcEventType.SendRPC && !advancedProperty.boolValue)).OrderBy(et => System.Enum.GetName(typeof(VRC_EventHandler.VrcEventType), et)))
  442. {
  443. menu.AddItem(new GUIContent("Basic Events/" + type.ToString()), false, (t) => {
  444. eventsList.arraySize++;
  445. SerializedProperty newEventProperty = eventsList.GetArrayElementAtIndex(eventsList.arraySize - 1);
  446. newEventProperty.FindPropertyRelative("EventType").intValue = (int)(VRC_EventHandler.VrcEventType)t;
  447. newEventProperty.FindPropertyRelative("ParameterObjects").arraySize = 0;
  448. newEventProperty.FindPropertyRelative("ParameterInt").intValue = 0;
  449. newEventProperty.FindPropertyRelative("ParameterFloat").floatValue = 0f;
  450. newEventProperty.FindPropertyRelative("ParameterString").stringValue = null;
  451. serializedObject.ApplyModifiedProperties();
  452. }, type);
  453. }
  454. VRCSDK2.IVRCEventProvider[] providers = FindObjectsOfType<MonoBehaviour>().Where(b => b is IVRCEventProvider).Cast<IVRCEventProvider>().ToArray();
  455. foreach (VRCSDK2.IVRCEventProvider provider in providers)
  456. {
  457. foreach (VRC_EventHandler.VrcEvent evt in provider.ProvideEvents())
  458. {
  459. string name = "Events from Scene/" + (provider as MonoBehaviour).name + "/" + evt.Name;
  460. menu.AddItem(new GUIContent(name), false, (t) => {
  461. eventsList.arraySize++;
  462. VRC_EventHandler.VrcEvent e = (VRC_EventHandler.VrcEvent)t;
  463. SerializedProperty newEventProperty = eventsList.GetArrayElementAtIndex(eventsList.arraySize - 1);
  464. newEventProperty.FindPropertyRelative("Name").stringValue = e.Name;
  465. newEventProperty.FindPropertyRelative("EventType").intValue = (int)e.EventType;
  466. newEventProperty.FindPropertyRelative("ParameterInt").intValue = e.ParameterInt;
  467. newEventProperty.FindPropertyRelative("ParameterFloat").floatValue = e.ParameterFloat;
  468. newEventProperty.FindPropertyRelative("ParameterString").stringValue = e.ParameterString;
  469. newEventProperty.FindPropertyRelative("ParameterObjects").arraySize = e.ParameterObjects.Length;
  470. for (int obj_idx = 0; obj_idx < e.ParameterObjects.Length; ++obj_idx)
  471. newEventProperty.FindPropertyRelative("ParameterObjects").GetArrayElementAtIndex(obj_idx).objectReferenceValue = e.ParameterObjects[obj_idx];
  472. #pragma warning disable CS0618 // Type or member is obsolete
  473. newEventProperty.FindPropertyRelative("ParameterObject").objectReferenceValue = e.ParameterObject;
  474. #pragma warning restore CS0618 // Type or member is obsolete
  475. serializedObject.ApplyModifiedProperties();
  476. }, evt);
  477. }
  478. }
  479. menu.ShowAsContext();
  480. eventLists = new ReorderableList[0];
  481. objectLists = new ReorderableList[0];
  482. relayLists = new ReorderableList[0];
  483. };
  484. eventLists[idx] = newList;
  485. }
  486. ReorderableList eventList = eventLists[idx];
  487. eventList.DoLayoutList();
  488. }
  489. private void RenderDataStorage(SerializedProperty triggerProperty)
  490. {
  491. if (triggerProperty.serializedObject.targetObjects.Any(obj => (obj as VRC_Trigger).gameObject.GetComponent<VRC_DataStorage>() == null))
  492. RenderHelpBox("Data Storage Triggers require a VRC_DataStorage Component.", MessageType.Warning);
  493. else
  494. {
  495. SerializedProperty idxProperty = triggerProperty.FindPropertyRelative("DataElementIdx");
  496. VRC_DataStorage ds = (target as VRC_Trigger).gameObject.GetComponent<VRC_DataStorage>();
  497. if (ds.data == null)
  498. {
  499. ds.data = new VRC_DataStorage.VrcDataElement[0];
  500. idxProperty.intValue = -1;
  501. }
  502. List<string> names = new List<string>();
  503. names.Add("Any Data Element");
  504. foreach (VRC_DataStorage.VrcDataElement element in ds.data)
  505. names.Add(element.name);
  506. int selectedIdx = idxProperty.intValue;
  507. if (selectedIdx == -1)
  508. selectedIdx = 0;
  509. else
  510. selectedIdx += 1;
  511. selectedIdx = EditorGUILayout.Popup("Data Element", selectedIdx, names.ToArray());
  512. if (selectedIdx == 0)
  513. idxProperty.intValue = -1;
  514. else
  515. idxProperty.intValue = selectedIdx - 1;
  516. }
  517. }
  518. private void RenderKey(SerializedProperty triggerProperty)
  519. {
  520. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("Key"));
  521. }
  522. private void RenderCollider(SerializedProperty triggerProperty)
  523. {
  524. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("TriggerIndividuals"));
  525. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("Layers"));
  526. }
  527. private void RenderTimer(SerializedProperty triggerProperty)
  528. {
  529. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("Repeat"));
  530. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("ResetOnEnable"));
  531. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("LowPeriodTime"));
  532. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("HighPeriodTime"));
  533. }
  534. private void RenderCustom(SerializedProperty triggerProperty)
  535. {
  536. SerializedProperty nameProperty = triggerProperty.FindPropertyRelative("Name");
  537. EditorGUILayout.PropertyField(triggerProperty.FindPropertyRelative("Name"));
  538. if (string.IsNullOrEmpty(nameProperty.stringValue))
  539. nameProperty.stringValue = "Unnamed";
  540. }
  541. private void RenderRelay(SerializedProperty triggerProperty, int idx)
  542. {
  543. if (relayLists[idx] == null)
  544. {
  545. ReorderableList newList = new ReorderableList(serializedObject, triggerProperty.FindPropertyRelative("Others"), true, true, true, true);
  546. newList.drawHeaderCallback = (Rect rect) => EditorGUI.LabelField(rect, new GUIContent("Targets"));
  547. newList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
  548. {
  549. SerializedProperty target = newList.serializedProperty.GetArrayElementAtIndex(index);
  550. EditorGUI.PropertyField(rect, target, GUIContent.none);
  551. target.serializedObject.ApplyModifiedProperties();
  552. };
  553. relayLists[idx] = newList;
  554. }
  555. relayLists[idx].DoLayoutList();
  556. }
  557. private void RenderEmpty(SerializedProperty triggerProperty)
  558. {
  559. }
  560. private bool doesPropertyContainAnyNullReceivers(SerializedProperty objectsProperty)
  561. {
  562. bool containsNullReceivers = false;
  563. if (objectsProperty.arraySize > 0)
  564. {
  565. for (int i = 0; i < objectsProperty.arraySize; i++)
  566. {
  567. SerializedProperty elem = objectsProperty.GetArrayElementAtIndex(i);
  568. if (elem.objectReferenceValue == null) containsNullReceivers = true;
  569. }
  570. }
  571. return containsNullReceivers;
  572. }
  573. private void RenderTargetGameObjectList(SerializedProperty objectsProperty, int idx, bool receiverRequired = true)
  574. {
  575. if (objectLists[idx] == null)
  576. {
  577. objectLists[idx] = new ReorderableList(objectsProperty.serializedObject, objectsProperty, true, true, true, true);
  578. objectLists[idx].drawHeaderCallback = (Rect rect) =>
  579. {
  580. string infoString = "Receivers";
  581. if (objectsProperty.arraySize == 0)
  582. infoString = "Receivers: This GameObject";
  583. EditorGUI.LabelField(rect, new GUIContent(infoString));
  584. Event evt = Event.current;
  585. if (!rect.Contains(evt.mousePosition))
  586. return;
  587. if (evt.type == EventType.DragUpdated)
  588. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  589. if (evt.type == EventType.DragPerform)
  590. {
  591. GameObject[] dragObjects = DragAndDrop.objectReferences.OfType<GameObject>().ToArray();
  592. int startIndex = objectsProperty.arraySize;
  593. objectsProperty.arraySize = objectsProperty.arraySize + dragObjects.Length;
  594. for (int i = 0; i < dragObjects.Length; i++)
  595. {
  596. SerializedProperty newElem = objectsProperty.GetArrayElementAtIndex(startIndex + i);
  597. newElem.objectReferenceValue = dragObjects[i];
  598. }
  599. DragAndDrop.AcceptDrag();
  600. evt.Use();
  601. }
  602. };
  603. objectLists[idx].drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
  604. {
  605. SerializedProperty target = objectLists[idx].serializedProperty.GetArrayElementAtIndex(index);
  606. EditorGUI.PropertyField(rect, target, GUIContent.none);
  607. target.serializedObject.ApplyModifiedProperties();
  608. };
  609. }
  610. objectLists[idx].DoLayoutList();
  611. if (objectsProperty.arraySize == 0)
  612. RenderHelpBox("This trigger will target the GameObject it's on, because the receivers list is empty.", MessageType.Error);
  613. else if (receiverRequired && doesPropertyContainAnyNullReceivers(objectsProperty))
  614. RenderHelpBox("Trigger with no object set will be ignored!", MessageType.Info);
  615. }
  616. private void RenderTargetComponentList<T>(SerializedProperty objectsProperty, int idx, string label = "Receivers") where T : Component
  617. {
  618. if (objectLists[idx] == null)
  619. {
  620. objectLists[idx] = new ReorderableList(objectsProperty.serializedObject, objectsProperty, true, true, true, true);
  621. objectLists[idx].drawHeaderCallback = (Rect rect) =>
  622. {
  623. string infoString = label;
  624. if (objectsProperty.arraySize == 0)
  625. infoString = label + ": This " + typeof(T).Name;
  626. EditorGUI.LabelField(rect, new GUIContent(infoString));
  627. Event evt = Event.current;
  628. if (!rect.Contains(evt.mousePosition))
  629. return;
  630. if (evt.type == EventType.DragUpdated)
  631. DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
  632. if (evt.type == EventType.DragPerform)
  633. {
  634. GameObject[] dragObjects = DragAndDrop.objectReferences.OfType<GameObject>().ToArray();
  635. int startIndex = objectsProperty.arraySize;
  636. objectsProperty.arraySize = objectsProperty.arraySize + dragObjects.Length;
  637. for (int i = 0; i < dragObjects.Length; i++)
  638. {
  639. SerializedProperty newElem = objectsProperty.GetArrayElementAtIndex(startIndex + i);
  640. newElem.objectReferenceValue = dragObjects[i];
  641. }
  642. DragAndDrop.AcceptDrag();
  643. evt.Use();
  644. }
  645. };
  646. objectLists[idx].drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
  647. {
  648. SerializedProperty target = objectLists[idx].serializedProperty.GetArrayElementAtIndex(index);
  649. T current = null;
  650. if (target.objectReferenceValue != null)
  651. current = (target.objectReferenceValue as GameObject).GetComponent<T>();
  652. current = EditorGUI.ObjectField(rect, current, typeof(T), true) as T;
  653. target.objectReferenceValue = current == null ? null : current.gameObject;
  654. target.serializedObject.ApplyModifiedProperties();
  655. };
  656. }
  657. objectLists[idx].DoLayoutList();
  658. if (objectsProperty.arraySize == 0)
  659. RenderHelpBox("This trigger will target the GameObject it's on, because the receivers list is empty.", MessageType.Error);
  660. else if (doesPropertyContainAnyNullReceivers(objectsProperty))
  661. RenderHelpBox("Trigger with no object set will be ignored!", MessageType.Info);
  662. }
  663. public void RenderEventEditor(SerializedProperty shadowProperty, SerializedProperty triggerProperty, SerializedProperty eventProperty, int triggerIdx)
  664. {
  665. SerializedProperty eventTypeProperty = eventProperty.FindPropertyRelative("EventType");
  666. SerializedProperty parameterObjectProperty = eventProperty.FindPropertyRelative("ParameterObject");
  667. SerializedProperty parameterObjectsProperty = eventProperty.FindPropertyRelative("ParameterObjects");
  668. SerializedProperty parameterStringProperty = eventProperty.FindPropertyRelative("ParameterString");
  669. SerializedProperty parameterBoolOpProperty = eventProperty.FindPropertyRelative("ParameterBoolOp");
  670. SerializedProperty parameterFloatProperty = eventProperty.FindPropertyRelative("ParameterFloat");
  671. SerializedProperty parameterIntProperty = eventProperty.FindPropertyRelative("ParameterInt");
  672. SerializedProperty parameterBytesProperty = eventProperty.FindPropertyRelative("ParameterBytes");
  673. if (parameterObjectProperty.objectReferenceValue != null && parameterObjectsProperty.arraySize == 0)
  674. {
  675. parameterObjectsProperty.arraySize = 1;
  676. parameterObjectsProperty.GetArrayElementAtIndex(0).objectReferenceValue = parameterObjectProperty.objectReferenceValue;
  677. }
  678. parameterObjectProperty.objectReferenceValue = null;
  679. switch ((VRC_EventHandler.VrcEventType)eventTypeProperty.intValue)
  680. {
  681. case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationBool:
  682. {
  683. RenderTargetComponentList<Animator>(parameterObjectsProperty, triggerIdx);
  684. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Variable"));
  685. RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Operation"), true);
  686. break;
  687. }
  688. case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationFloat:
  689. {
  690. RenderTargetComponentList<Animator>(parameterObjectsProperty, triggerIdx);
  691. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Variable"));
  692. RenderPropertyEditor(shadowProperty, parameterFloatProperty, new GUIContent("Value"));
  693. break;
  694. }
  695. case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationInt:
  696. case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationIntAdd:
  697. case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationIntDivide:
  698. case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationIntMultiply:
  699. case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationIntSubtract:
  700. {
  701. RenderTargetComponentList<Animator>(parameterObjectsProperty, triggerIdx);
  702. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Variable"));
  703. RenderPropertyEditor(shadowProperty, parameterIntProperty, new GUIContent("Value"));
  704. break;
  705. }
  706. case VRCSDK2.VRC_EventHandler.VrcEventType.AnimationTrigger:
  707. {
  708. RenderTargetComponentList<Animator>(parameterObjectsProperty, triggerIdx);
  709. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Trigger"));
  710. break;
  711. }
  712. case VRCSDK2.VRC_EventHandler.VrcEventType.PlayAnimation:
  713. {
  714. RenderTargetComponentList<Animation>(parameterObjectsProperty, triggerIdx);
  715. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Clip"));
  716. for (int idx = 0; idx < parameterObjectsProperty.arraySize; ++idx)
  717. {
  718. GameObject obj = parameterObjectsProperty.GetArrayElementAtIndex(idx).objectReferenceValue as GameObject;
  719. Animation anim = obj == null ? null : obj.GetComponent<Animation>();
  720. if (anim != null && anim.GetClip(parameterStringProperty.stringValue) == null)
  721. {
  722. RenderHelpBox("Could not locate " + parameterStringProperty.stringValue + " on " + obj.name + "; is it legacy?", MessageType.Error);
  723. break;
  724. }
  725. }
  726. break;
  727. }
  728. case VRCSDK2.VRC_EventHandler.VrcEventType.AudioTrigger:
  729. {
  730. RenderTargetComponentList<AudioSource>(parameterObjectsProperty, triggerIdx);
  731. List<string> clipNames = new List<string>();
  732. if (parameterObjectsProperty.arraySize > 0)
  733. {
  734. int idx = 0;
  735. for (; idx < parameterObjectsProperty.arraySize; ++idx)
  736. {
  737. SerializedProperty prop = parameterObjectsProperty.GetArrayElementAtIndex(0);
  738. GameObject obj = prop.objectReferenceValue != null ? prop.objectReferenceValue as GameObject : null;
  739. if (obj != null)
  740. {
  741. foreach (AudioSource source in obj.GetComponents<AudioSource>())
  742. if (source.clip != null && !string.IsNullOrEmpty(source.clip.name))
  743. clipNames.Add(source.clip.name);
  744. break;
  745. }
  746. }
  747. for (; idx < parameterObjectsProperty.arraySize; ++idx)
  748. {
  749. SerializedProperty prop = parameterObjectsProperty.GetArrayElementAtIndex(0);
  750. GameObject obj = prop.objectReferenceValue != null ? prop.objectReferenceValue as GameObject : null;
  751. if (obj != null)
  752. {
  753. List<string> thisClipNames = new List<string>();
  754. foreach (AudioSource source in obj.GetComponents<AudioSource>())
  755. if (source.clip != null && !string.IsNullOrEmpty(source.clip.name))
  756. thisClipNames.Add(source.clip.name);
  757. clipNames.RemoveAll(s => thisClipNames.Contains(s) == false);
  758. }
  759. }
  760. }
  761. clipNames.Insert(0, "");
  762. int selectedIdx;
  763. for (selectedIdx = clipNames.Count - 1; selectedIdx > 0; --selectedIdx)
  764. if (parameterStringProperty.stringValue == clipNames[selectedIdx])
  765. break;
  766. parameterStringProperty.stringValue = clipNames[EditorGUILayout.Popup("Clip", selectedIdx, clipNames.ToArray())];
  767. break;
  768. }
  769. #pragma warning disable CS0618 // Type or member is obsolete
  770. case VRCSDK2.VRC_EventHandler.VrcEventType.MeshVisibility:
  771. #pragma warning restore CS0618 // Type or member is obsolete
  772. {
  773. RenderTargetComponentList<Renderer>(parameterObjectsProperty, triggerIdx);
  774. RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Operation"), true);
  775. break;
  776. }
  777. case VRCSDK2.VRC_EventHandler.VrcEventType.RunConsoleCommand:
  778. {
  779. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Command"));
  780. break;
  781. }
  782. #pragma warning disable CS0618 // Type or member is obsolete
  783. case VRCSDK2.VRC_EventHandler.VrcEventType.SendMessage:
  784. #pragma warning restore CS0618 // Type or member is obsolete
  785. {
  786. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  787. if (parameterObjectsProperty.arraySize > 0)
  788. RenderMethodSelector(eventProperty);
  789. }
  790. break;
  791. case VRCSDK2.VRC_EventHandler.VrcEventType.SetGameObjectActive:
  792. {
  793. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  794. RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Operation"), true);
  795. break;
  796. }
  797. case VRCSDK2.VRC_EventHandler.VrcEventType.SetParticlePlaying:
  798. {
  799. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  800. RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Operation"), true);
  801. break;
  802. }
  803. case VRCSDK2.VRC_EventHandler.VrcEventType.TeleportPlayer:
  804. {
  805. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  806. RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Align Room To Destination"), true);
  807. break;
  808. }
  809. case VRCSDK2.VRC_EventHandler.VrcEventType.SetWebPanelURI:
  810. {
  811. RenderTargetComponentList<VRCSDK2.VRC_WebPanel>(parameterObjectsProperty, triggerIdx);
  812. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("URI"));
  813. break;
  814. }
  815. case VRCSDK2.VRC_EventHandler.VrcEventType.SetWebPanelVolume:
  816. {
  817. RenderTargetComponentList<VRCSDK2.VRC_WebPanel>(parameterObjectsProperty, triggerIdx);
  818. parameterFloatProperty.floatValue = EditorGUILayout.Slider("Volume", parameterFloatProperty.floatValue, 0f, 1f);
  819. break;
  820. }
  821. case VRCSDK2.VRC_EventHandler.VrcEventType.SendRPC:
  822. {
  823. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  824. if (parameterObjectsProperty.arraySize > 0)
  825. {
  826. RenderMethodSelector(eventProperty);
  827. RenderRPCParameterEditor(eventProperty);
  828. }
  829. }
  830. break;
  831. case VRC_EventHandler.VrcEventType.ActivateCustomTrigger:
  832. {
  833. RenderTargetComponentList<VRC_Trigger>(parameterObjectsProperty, triggerIdx);
  834. VRC_EditorTools.CustomTriggerPopup("Name", parameterObjectsProperty, parameterStringProperty);
  835. }
  836. break;
  837. case VRC_EventHandler.VrcEventType.SpawnObject:
  838. {
  839. VRC_SceneDescriptor scene = FindObjectOfType<VRC_SceneDescriptor>();
  840. string path = parameterStringProperty.stringValue;
  841. GameObject found = scene != null ? scene.DynamicPrefabs.FirstOrDefault(p => AssetDatabase.GetAssetOrScenePath(p) == path) : null;
  842. found = found == null ? AssetDatabase.LoadAssetAtPath<GameObject>(path) : found;
  843. GameObject newFound = EditorGUILayout.ObjectField("Prefab", found, typeof(GameObject), false) as GameObject;
  844. parameterStringProperty.stringValue = newFound == null ? null : AssetDatabase.GetAssetOrScenePath(newFound);
  845. RenderTargetComponentList<Transform>(parameterObjectsProperty, triggerIdx, "Locations");
  846. }
  847. break;
  848. case VRC_EventHandler.VrcEventType.DestroyObject:
  849. {
  850. SerializedProperty broadcastTypeProperty = triggerProperty.FindPropertyRelative("BroadcastType");
  851. VRC_EventHandler.VrcBroadcastType broadcast = (VRC_EventHandler.VrcBroadcastType)broadcastTypeProperty.intValue;
  852. if (broadcast != VRC_EventHandler.VrcBroadcastType.Always && broadcast != VRC_EventHandler.VrcBroadcastType.AlwaysUnbuffered && broadcast != VRC_EventHandler.VrcBroadcastType.AlwaysBufferOne)
  853. RenderHelpBox("Not all clients will destroy the object.", MessageType.Warning);
  854. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  855. }
  856. break;
  857. case VRC_EventHandler.VrcEventType.SetLayer:
  858. {
  859. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  860. parameterIntProperty.intValue = (int)EditorGUILayout.LayerField("Layer", parameterIntProperty.intValue);
  861. }
  862. break;
  863. case VRC_EventHandler.VrcEventType.SetMaterial:
  864. {
  865. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  866. VRC_SceneDescriptor scene = FindObjectOfType<VRC_SceneDescriptor>();
  867. string path = parameterStringProperty.stringValue;
  868. Material found = scene != null ? scene.DynamicMaterials.FirstOrDefault(p => AssetDatabase.GetAssetOrScenePath(p) == path) : null;
  869. found = found == null ? AssetDatabase.LoadAssetAtPath<Material>(path) : found;
  870. Material newFound = EditorGUILayout.ObjectField("Material", found, typeof(Material), false) as Material;
  871. parameterStringProperty.stringValue = newFound == null ? null : AssetDatabase.GetAssetOrScenePath(newFound);
  872. if (scene != null && found != newFound)
  873. {
  874. scene.DynamicMaterials.Add(newFound);
  875. scene.DynamicMaterials.Remove(found);
  876. }
  877. }
  878. break;
  879. case VRC_EventHandler.VrcEventType.AddDamage:
  880. {
  881. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx, false);
  882. RenderPropertyEditor(shadowProperty, parameterFloatProperty, new GUIContent("Damage"));
  883. }
  884. break;
  885. case VRC_EventHandler.VrcEventType.AddHealth:
  886. {
  887. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx, false);
  888. RenderPropertyEditor(shadowProperty, parameterFloatProperty, new GUIContent("Health"));
  889. }
  890. break;
  891. case VRC_EventHandler.VrcEventType.SetComponentActive:
  892. {
  893. RenderTargetGameObjectList(parameterObjectsProperty, triggerIdx);
  894. if (RenderTargetComponentEditor(parameterStringProperty, parameterObjectsProperty, triggerIdx))
  895. RenderPropertyEditor(shadowProperty, parameterBoolOpProperty, new GUIContent("Enable"), true);
  896. }
  897. break;
  898. case VRC_EventHandler.VrcEventType.AddVelocity:
  899. case VRC_EventHandler.VrcEventType.SetVelocity:
  900. {
  901. RenderTargetComponentList<Rigidbody>(parameterObjectsProperty, triggerIdx);
  902. RenderVector3andSpacePropertyEditor(parameterBytesProperty, new GUIContent("Velocity"));
  903. }
  904. break;
  905. case VRC_EventHandler.VrcEventType.AddAngularVelocity:
  906. case VRC_EventHandler.VrcEventType.SetAngularVelocity:
  907. {
  908. RenderTargetComponentList<Rigidbody>(parameterObjectsProperty, triggerIdx);
  909. RenderVector3andSpacePropertyEditor(parameterBytesProperty, new GUIContent("Angular Velocity"));
  910. }
  911. break;
  912. case VRC_EventHandler.VrcEventType.AddForce:
  913. {
  914. RenderTargetComponentList<Rigidbody>(parameterObjectsProperty, triggerIdx);
  915. RenderVector3andSpacePropertyEditor(parameterBytesProperty, new GUIContent("Force"));
  916. }
  917. break;
  918. case VRC_EventHandler.VrcEventType.SetUIText:
  919. {
  920. RenderTargetComponentList<Text>(parameterObjectsProperty, triggerIdx);
  921. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Text"));
  922. }
  923. break;
  924. #if UDON
  925. case VRC_EventHandler.VrcEventType.CallUdonMethod:
  926. {
  927. RenderTargetComponentList<VRC.Udon.UdonBehaviour>(parameterObjectsProperty, triggerIdx);
  928. RenderPropertyEditor(shadowProperty, parameterStringProperty, new GUIContent("Method Name"));
  929. }
  930. break;
  931. #endif
  932. default:
  933. RenderHelpBox("Unsupported event type", MessageType.Error);
  934. break;
  935. }
  936. }
  937. private void RenderVector3andSpacePropertyEditor(SerializedProperty propertyBytes, GUIContent label)
  938. {
  939. object[] parameters = null;
  940. parameters = VRCSDK2.VRC_Serialization.ParameterDecoder(VRC_EditorTools.ReadBytesFromProperty(propertyBytes));
  941. if (parameters.Length == 0)
  942. parameters = new object[1] { new Vector4() };
  943. EditorGUI.BeginChangeCheck();
  944. Vector3 vec3Field = EditorGUILayout.Vector3Field(label,new Vector3(((Vector4)parameters[0]).x, ((Vector4)parameters[0]).y, ((Vector4)parameters[0]).z));
  945. bool spaceField = EditorGUILayout.Toggle("Use World Space", ((Vector4)parameters[0]).w > .5f ? true : false);
  946. parameters[0] = new Vector4(vec3Field.x, vec3Field.y, vec3Field.z, Convert.ToSingle(spaceField));
  947. if (EditorGUI.EndChangeCheck())
  948. {
  949. VRC_EditorTools.WriteBytesToProperty(propertyBytes, VRCSDK2.VRC_Serialization.ParameterEncoder(parameters));
  950. }
  951. }
  952. private void RenderVector3PropertyEditor(SerializedProperty propertyBytes, GUIContent label)
  953. {
  954. object[] parameters = null;
  955. parameters = VRCSDK2.VRC_Serialization.ParameterDecoder(VRC_EditorTools.ReadBytesFromProperty(propertyBytes));
  956. if (parameters.Length == 0)
  957. parameters = new object[1] { new Vector3() };
  958. EditorGUI.BeginChangeCheck();
  959. parameters[0] = EditorGUILayout.Vector3Field(label, (Vector3)parameters[0]);
  960. if (EditorGUI.EndChangeCheck())
  961. {
  962. VRC_EditorTools.WriteBytesToProperty(propertyBytes, VRCSDK2.VRC_Serialization.ParameterEncoder(parameters));
  963. }
  964. }
  965. bool RenderTargetComponentEditor(SerializedProperty componentNameProperty, SerializedProperty objectsProperty, int triggerIdx)
  966. {
  967. if (!objectsProperty.isArray || objectsProperty.arraySize == 0)
  968. return false;
  969. HashSet<Type> behaviours = new HashSet<Type>();
  970. bool isFirst = true;
  971. for (int objIdx = 0; objIdx < objectsProperty.arraySize; ++objIdx)
  972. {
  973. if (objectsProperty.GetArrayElementAtIndex(objIdx) == null || objectsProperty.GetArrayElementAtIndex(objIdx).objectReferenceValue == null || !(objectsProperty.GetArrayElementAtIndex(objIdx).objectReferenceValue is GameObject))
  974. continue;
  975. if (isFirst)
  976. {
  977. foreach (Component component in (objectsProperty.GetArrayElementAtIndex(0).objectReferenceValue as GameObject).GetComponents(typeof(Component)))
  978. {
  979. Type t = component.GetType();
  980. if (t.GetProperty("enabled") != null)
  981. behaviours.Add(component.GetType());
  982. }
  983. isFirst = false;
  984. }
  985. else
  986. {
  987. HashSet<Type> thisBehaviours = new HashSet<Type>();
  988. foreach (Component component in (objectsProperty.GetArrayElementAtIndex(objIdx).objectReferenceValue as GameObject).GetComponents(typeof(Component)))
  989. {
  990. Type t = component.GetType();
  991. if (t.GetProperty("enabled") != null)
  992. thisBehaviours.Add(component.GetType());
  993. }
  994. behaviours.RemoveWhere(s => thisBehaviours.Contains(s) == false);
  995. }
  996. }
  997. if (behaviours.Count == 0)
  998. return false;
  999. Type[] types = behaviours.ToArray();
  1000. string[] options = behaviours.Select(t => t.FullName).ToArray();
  1001. int selectedIdx = 0;
  1002. for (int typeIdx = 0; typeIdx < types.Length; ++typeIdx)
  1003. if (types[typeIdx].FullName == componentNameProperty.stringValue)
  1004. {
  1005. selectedIdx = typeIdx;
  1006. break;
  1007. }
  1008. selectedIdx = EditorGUILayout.Popup("Component", selectedIdx, options);
  1009. componentNameProperty.stringValue = types[selectedIdx].FullName;
  1010. return true;
  1011. }
  1012. void RenderRPCParameterEditor(SerializedProperty eventProperty)
  1013. {
  1014. EditorGUI.BeginChangeCheck();
  1015. SerializedProperty parameterIntProperty = eventProperty.FindPropertyRelative("ParameterInt");
  1016. SerializedProperty parameterObjectsProperty = eventProperty.FindPropertyRelative("ParameterObjects");
  1017. SerializedProperty parameterStringProperty = eventProperty.FindPropertyRelative("ParameterString");
  1018. SerializedProperty parameterBytesProperty = eventProperty.FindPropertyRelative("ParameterBytes");
  1019. if (parameterIntProperty.intValue == -1)
  1020. parameterIntProperty.intValue = (int)(VRCSDK2.VRC_EventHandler.VrcTargetType.All);
  1021. if (advancedProperty.boolValue)
  1022. {
  1023. parameterIntProperty.intValue = (int)VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_EventHandler.VrcTargetType>("Targets", (VRCSDK2.VRC_EventHandler.VrcTargetType)parameterIntProperty.intValue, e => e != VRC_EventHandler.VrcTargetType.TargetPlayer);
  1024. string message = null;
  1025. switch ((VRCSDK2.VRC_EventHandler.VrcTargetType)parameterIntProperty.intValue)
  1026. {
  1027. case VRC_EventHandler.VrcTargetType.All:
  1028. message = "Will execute on all clients, except for those that join later.";
  1029. break;
  1030. case VRC_EventHandler.VrcTargetType.AllBuffered:
  1031. message = "Will execute on all clients, including those that join later.";
  1032. break;
  1033. case VRC_EventHandler.VrcTargetType.Local:
  1034. message = "Will execute for the instigator only.";
  1035. break;
  1036. case VRC_EventHandler.VrcTargetType.Master:
  1037. message = "Will execute on the Master.";
  1038. break;
  1039. case VRC_EventHandler.VrcTargetType.Others:
  1040. message = "Will execute for others but not locally, except for those that join later.";
  1041. break;
  1042. case VRC_EventHandler.VrcTargetType.OthersBuffered:
  1043. message = "Will execute for others but not locally, including those that join later.";
  1044. break;
  1045. case VRC_EventHandler.VrcTargetType.Owner:
  1046. message = "Will execute on the Owner.";
  1047. break;
  1048. case VRC_EventHandler.VrcTargetType.AllBufferOne:
  1049. message = "Will execute on all clients, and only the most recent is executed for those that join later.";
  1050. break;
  1051. case VRC_EventHandler.VrcTargetType.OthersBufferOne:
  1052. message = "Will execute for others but not locally, and only the most recent is executed for those that join later.";
  1053. break;
  1054. }
  1055. if (message != null)
  1056. RenderHelpBox(message, MessageType.Info);
  1057. }
  1058. Dictionary<string, List<MethodInfo>> methods = VRC_EditorTools.GetSharedAccessibleMethodsOnGameObjects(parameterObjectsProperty);
  1059. if (methods.Count == 0)
  1060. {
  1061. RenderHelpBox("No applicable methods found.", MessageType.Error);
  1062. return;
  1063. }
  1064. List<MethodInfo> methodInfos = methods.Values.Aggregate(new List<MethodInfo>(), (acc, lst) => { acc.AddRange(lst); return acc; });
  1065. MethodInfo info = methodInfos.FirstOrDefault(m => m.Name == parameterStringProperty.stringValue);
  1066. if (info == null)
  1067. return;
  1068. ParameterInfo[] paramInfo = info.GetParameters();
  1069. object[] parameters = null;
  1070. if (rpcByteCache.ContainsKey(eventProperty.propertyPath))
  1071. parameters = rpcByteCache[eventProperty.propertyPath];
  1072. else
  1073. {
  1074. parameters = VRCSDK2.VRC_Serialization.ParameterDecoder(VRC_EditorTools.ReadBytesFromProperty(parameterBytesProperty));
  1075. rpcByteCache.Add(eventProperty.propertyPath, parameters);
  1076. }
  1077. if (parameters == null)
  1078. parameters = new object[paramInfo.Length];
  1079. if (parameters.Length != paramInfo.Length)
  1080. Array.Resize(ref parameters, paramInfo.Length);
  1081. bool finalIntAsPlayerID = false;
  1082. EditorGUI.BeginChangeCheck();
  1083. for (int idx = 0; idx < parameters.Length; ++idx)
  1084. {
  1085. Type paramType = paramInfo[idx].ParameterType;
  1086. if (paramType == typeof(Color))
  1087. {
  1088. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1089. parameters[idx] = Color.black;
  1090. parameters[idx] = EditorGUILayout.ColorField(paramInfo[idx].Name, (Color)parameters[idx]);
  1091. }
  1092. else if (paramType == typeof(bool))
  1093. {
  1094. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1095. parameters[idx] = false;
  1096. parameters[idx] = EditorGUILayout.Toggle(paramInfo[idx].Name, (bool)parameters[idx]);
  1097. }
  1098. else if (paramType.IsEnum)
  1099. {
  1100. // make an array of strings of the enum values
  1101. var values = Enum.GetValues(paramType);
  1102. string[] itemStrings = new string[values.Length];
  1103. int i=0;
  1104. foreach (var item in Enum.GetValues(paramType))
  1105. {
  1106. itemStrings[i++] = item.ToString();
  1107. }
  1108. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1109. parameters[idx] = Enum.Parse(paramType, itemStrings[0]);
  1110. parameters[idx] = Enum.Parse( paramType, itemStrings[ EditorGUILayout.Popup(paramInfo[idx].Name, (int)parameters[idx], itemStrings) ] );
  1111. }
  1112. else if (paramType == typeof(double))
  1113. {
  1114. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1115. parameters[idx] = 0d;
  1116. parameters[idx] = EditorGUILayout.DoubleField(paramInfo[idx].Name, (double)parameters[idx]);
  1117. }
  1118. else if (paramType == typeof(float))
  1119. {
  1120. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1121. parameters[idx] = 0f;
  1122. parameters[idx] = EditorGUILayout.FloatField(paramInfo[idx].Name, (float)parameters[idx]);
  1123. }
  1124. else if (paramType == typeof(int))
  1125. {
  1126. if (idx == parameters.Length - 1)
  1127. finalIntAsPlayerID = !advancedProperty.boolValue || EditorGUILayout.Toggle("Use Player ID as last", finalIntAsPlayerID || parameters[idx] == null);
  1128. if (!finalIntAsPlayerID)
  1129. {
  1130. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1131. parameters[idx] = 0;
  1132. parameters[idx] = EditorGUILayout.IntField(paramInfo[idx].Name, (int)parameters[idx]);
  1133. }
  1134. }
  1135. else if (paramType == typeof(long))
  1136. {
  1137. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1138. parameters[idx] = 0;
  1139. parameters[idx] = EditorGUILayout.LongField(paramInfo[idx].Name, (long)parameters[idx]);
  1140. }
  1141. else if (paramType == typeof(UnityEngine.Rect))
  1142. {
  1143. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1144. parameters[idx] = new Rect();
  1145. parameters[idx] = EditorGUILayout.RectField(paramInfo[idx].Name, (UnityEngine.Rect)parameters[idx]);
  1146. }
  1147. else if (paramType == typeof(string))
  1148. {
  1149. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1150. parameters[idx] = "";
  1151. parameters[idx] = EditorGUILayout.TextField(paramInfo[idx].Name, (string)parameters[idx]);
  1152. }
  1153. else if (paramType == typeof(Vector2))
  1154. {
  1155. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1156. parameters[idx] = new Vector2();
  1157. parameters[idx] = EditorGUILayout.Vector2Field(paramInfo[idx].Name, (Vector2)parameters[idx]);
  1158. }
  1159. else if (paramType == typeof(Vector3))
  1160. {
  1161. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1162. parameters[idx] = new Vector3();
  1163. parameters[idx] = EditorGUILayout.Vector3Field(paramInfo[idx].Name, (Vector3)parameters[idx]);
  1164. }
  1165. else if (paramType == typeof(Vector4))
  1166. {
  1167. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1168. parameters[idx] = new Vector4();
  1169. parameters[idx] = EditorGUILayout.Vector4Field(paramInfo[idx].Name, (Vector4)parameters[idx]);
  1170. }
  1171. else if (paramType == typeof(Quaternion))
  1172. {
  1173. if (parameters[idx] == null || parameters[idx].GetType() != paramType)
  1174. parameters[idx] = new Quaternion();
  1175. parameters[idx] = Quaternion.Euler(EditorGUILayout.Vector3Field(paramInfo[idx].Name, ((Quaternion)parameters[idx]).eulerAngles));
  1176. }
  1177. else if (paramType == typeof(UnityEngine.Object) || paramType.IsSubclassOf(typeof(UnityEngine.Object)))
  1178. {
  1179. if (parameters[idx] != null && parameters[idx].GetType() != paramType)
  1180. parameters[idx] = null;
  1181. parameters[idx] = EditorGUILayout.ObjectField(paramInfo[idx].Name, (UnityEngine.Object)parameters[idx], paramType, true);
  1182. }
  1183. else
  1184. EditorGUILayout.LabelField("Unable to handle " + paramType.Name, EditorStyles.boldLabel);
  1185. }
  1186. if (finalIntAsPlayerID)
  1187. Array.Resize(ref parameters, parameters.Length - 1);
  1188. if (EditorGUI.EndChangeCheck())
  1189. {
  1190. VRC_EditorTools.WriteBytesToProperty(parameterBytesProperty, VRCSDK2.VRC_Serialization.ParameterEncoder(parameters));
  1191. rpcByteCache[eventProperty.propertyPath] = parameters;
  1192. }
  1193. }
  1194. void RenderMethodSelector(SerializedProperty eventProperty)
  1195. {
  1196. SerializedProperty parameterObjectsProperty = eventProperty.FindPropertyRelative("ParameterObjects");
  1197. SerializedProperty parameterStringProperty = eventProperty.FindPropertyRelative("ParameterString");
  1198. SerializedProperty parameterBytesProperty = eventProperty.FindPropertyRelative("ParameterBytes");
  1199. Dictionary<string, List<MethodInfo>> methods = VRC_EditorTools.GetSharedAccessibleMethodsOnGameObjects(parameterObjectsProperty);
  1200. if (methods.Count == 0)
  1201. return;
  1202. List<string> combined = methods
  1203. .Select(pair => pair.Value.Select(s => pair.Key + "." + s.Name))
  1204. .Aggregate((a, b) =>
  1205. {
  1206. var v = new List<string>();
  1207. v.AddRange(a);
  1208. v.AddRange(b);
  1209. return v;
  1210. }).ToList();
  1211. combined.Insert(0, "Custom Method");
  1212. int currentIndex = string.IsNullOrEmpty(parameterStringProperty.stringValue) ? 0 : combined.FindIndex(s =>
  1213. {
  1214. var split = s.Split('.');
  1215. return split.Length > 1 && s.Split('.')[1] == parameterStringProperty.stringValue;
  1216. });
  1217. if (currentIndex < 0 || currentIndex >= combined.Count)
  1218. currentIndex = 0;
  1219. int newIndex = EditorGUILayout.Popup("Method", currentIndex, combined.ToArray());
  1220. if (newIndex != currentIndex)
  1221. {
  1222. parameterStringProperty.stringValue = "";
  1223. parameterBytesProperty.arraySize = 0;
  1224. }
  1225. currentIndex = newIndex;
  1226. if (currentIndex == 0)
  1227. EditorGUILayout.PropertyField(parameterStringProperty, new GUIContent("Custom Method"));
  1228. else
  1229. parameterStringProperty.stringValue = combined[currentIndex].Split('.')[1];
  1230. }
  1231. private void RenderPropertyEditor(SerializedProperty shadowProperty, SerializedProperty property, GUIContent label, bool isBoolOp = false)
  1232. {
  1233. VRC_DataStorage ds = (target as VRC_Trigger).gameObject.GetComponent<VRC_DataStorage>();
  1234. if (ds != null && ds.data != null && ds.data.Length != 0 && shadowProperty != null)
  1235. {
  1236. EditorGUILayout.BeginHorizontal();
  1237. EditorGUILayout.PrefixLabel(label);
  1238. bool renderField = false;
  1239. switch (property.propertyType)
  1240. {
  1241. case SerializedPropertyType.Boolean:
  1242. {
  1243. SerializedProperty prop = shadowProperty.FindPropertyRelative("ParameterBoolOp");
  1244. List<string> vals = ds.data.Where(el => el.type == VRC_DataStorage.VrcDataType.Bool).Select(el => el.name).ToList();
  1245. renderField = !ListPopup(vals, prop);
  1246. }
  1247. break;
  1248. case SerializedPropertyType.Float:
  1249. {
  1250. SerializedProperty prop = shadowProperty.FindPropertyRelative("ParameterFloat");
  1251. List<string> vals = ds.data.Where(el => el.type == VRC_DataStorage.VrcDataType.Float).Select(el => el.name).ToList();
  1252. renderField = !ListPopup(vals, prop);
  1253. }
  1254. break;
  1255. case SerializedPropertyType.Integer:
  1256. {
  1257. SerializedProperty prop = shadowProperty.FindPropertyRelative("ParameterInt");
  1258. List<string> vals = ds.data.Where(el => el.type == VRC_DataStorage.VrcDataType.Int).Select(el => el.name).ToList();
  1259. renderField = !ListPopup(vals, prop);
  1260. }
  1261. break;
  1262. case SerializedPropertyType.String:
  1263. {
  1264. SerializedProperty prop = shadowProperty.FindPropertyRelative("ParameterString");
  1265. List<string> vals = ds.data.Where(el => el.type == VRC_DataStorage.VrcDataType.String).Select(el => el.name).ToList();
  1266. renderField = !ListPopup(vals, prop);
  1267. }
  1268. break;
  1269. default:
  1270. {
  1271. renderField = true;
  1272. }
  1273. break;
  1274. }
  1275. if (renderField)
  1276. EditorGUILayout.PropertyField(property, GUIContent.none);
  1277. EditorGUILayout.EndHorizontal();
  1278. }
  1279. else
  1280. {
  1281. if (isBoolOp)
  1282. VRC_EditorTools.FilteredEnumPopup<VRCSDK2.VRC_EventHandler.VrcBooleanOp>(label.text, property, s => s != VRC_EventHandler.VrcBooleanOp.Unused);
  1283. else
  1284. EditorGUILayout.PropertyField(property, label);
  1285. return;
  1286. }
  1287. }
  1288. private bool ListPopup(List<string> vals, SerializedProperty prop, bool custom = true)
  1289. {
  1290. if (vals.Count == 0)
  1291. return false;
  1292. if (custom)
  1293. vals.Insert(0, "Custom");
  1294. int selectedIdx = prop.stringValue == null ? 0 : vals.IndexOf(prop.stringValue);
  1295. if (selectedIdx < 0 || selectedIdx > vals.Count)
  1296. selectedIdx = 0;
  1297. int idx = EditorGUILayout.Popup(selectedIdx, vals.ToArray());
  1298. if (idx == 0 && custom)
  1299. {
  1300. prop.stringValue = null;
  1301. return false;
  1302. }
  1303. else
  1304. {
  1305. prop.stringValue = vals[idx];
  1306. return true;
  1307. }
  1308. }
  1309. }
  1310. }
  1311. #endif