From eb84bb298d2b95aec7b2ae12cbf25ac64f25379a Mon Sep 17 00:00:00 2001 From: tylermurphy534 Date: Sun, 6 Nov 2022 15:12:42 -0500 Subject: move to self host --- .../Udon/Editor/ProgramSources/Attributes.meta | 8 + .../UdonProgramSourceNewMenuAttribute.cs | 18 + .../UdonProgramSourceNewMenuAttribute.cs.meta | 11 + .../SerializedUdonProgramAssetEditor.cs | 57 + .../SerializedUdonProgramAssetEditor.cs.meta | 11 + .../Editor/ProgramSources/UdonAssemblyProgram.meta | 8 + .../UdonAssemblyProgramAsset.cs | 96 + .../UdonAssemblyProgramAsset.cs.meta | 11 + .../UdonAssemblyProgramAssetEditor.cs | 9 + .../UdonAssemblyProgramAssetEditor.cs.meta | 11 + .../UdonAssemblyProgramAssetImporter.cs | 27 + .../UdonAssemblyProgramAssetImporter.cs.meta | 11 + .../Editor/ProgramSources/UdonGraphProgram.meta | 8 + .../Editor/ProgramSources/UdonGraphProgram/UI.meta | 8 + .../UdonGraphProgram/UI/GraphView.meta | 8 + .../UdonGraphProgram/UI/GraphView/Fields.meta | 8 + .../UI/GraphView/Fields/ByteField.cs | 24 + .../UI/GraphView/Fields/ByteField.cs.meta | 11 + .../UI/GraphView/Fields/CharField.cs | 24 + .../UI/GraphView/Fields/CharField.cs.meta | 11 + .../UI/GraphView/Fields/DecimalField.cs | 23 + .../UI/GraphView/Fields/DecimalField.cs.meta | 3 + .../UI/GraphView/Fields/LayerMaskField.cs | 24 + .../UI/GraphView/Fields/LayerMaskField.cs.meta | 11 + .../UI/GraphView/Fields/QuaternionField.cs | 24 + .../UI/GraphView/Fields/QuaternionField.cs.meta | 11 + .../UI/GraphView/Fields/SByteField.cs | 23 + .../UI/GraphView/Fields/SByteField.cs.meta | 3 + .../UI/GraphView/Fields/ShortField.cs | 23 + .../UI/GraphView/Fields/ShortField.cs.meta | 3 + .../UI/GraphView/Fields/UnsignedIntegerField.cs | 23 + .../GraphView/Fields/UnsignedIntegerField.cs.meta | 3 + .../UI/GraphView/Fields/UnsignedLongField.cs | 23 + .../UI/GraphView/Fields/UnsignedLongField.cs.meta | 3 + .../UI/GraphView/Fields/UnsignedShortField.cs | 23 + .../UI/GraphView/Fields/UnsignedShortField.cs.meta | 3 + .../UI/GraphView/Fields/VRCUrlField.cs | 23 + .../UI/GraphView/Fields/VRCUrlField.cs.meta | 11 + .../UI/GraphView/GraphElements.meta | 8 + .../GraphElements/GraphElementExtension.cs | 81 + .../GraphElements/GraphElementExtension.cs.meta | 11 + .../UI/GraphView/GraphElements/UdonArrayEditor.cs | 86 + .../GraphElements/UdonArrayEditor.cs.meta | 11 + .../GraphView/GraphElements/UdonArrayInspector.cs | 156 ++ .../GraphElements/UdonArrayInspector.cs.meta | 11 + .../UI/GraphView/GraphElements/UdonComment.cs | 220 +++ .../UI/GraphView/GraphElements/UdonComment.cs.meta | 11 + .../UI/GraphView/GraphElements/UdonGraphElement.cs | 48 + .../GraphElements/UdonGraphElement.cs.meta | 11 + .../UI/GraphView/GraphElements/UdonGroup.cs | 213 ++ .../UI/GraphView/GraphElements/UdonGroup.cs.meta | 11 + .../UI/GraphView/GraphElements/UdonMinimap.cs | 57 + .../UI/GraphView/GraphElements/UdonMinimap.cs.meta | 11 + .../UI/GraphView/GraphElements/UdonNode.cs | 1093 ++++++++++ .../UI/GraphView/GraphElements/UdonNode.cs.meta | 11 + .../UI/GraphView/GraphElements/UdonNodes.meta | 8 + .../UdonNodes/GetOrSetProgramVariableNode.cs | 30 + .../UdonNodes/GetOrSetProgramVariableNode.cs.meta | 3 + .../GraphElements/UdonNodes/SendCustomEventNode.cs | 28 + .../UdonNodes/SendCustomEventNode.cs.meta | 3 + .../GraphElements/UdonNodes/SetReturnValueNode.cs | 42 + .../UdonNodes/SetReturnValueNode.cs.meta | 3 + .../GraphElements/UdonNodes/SetVariableNode.cs | 25 + .../UdonNodes/SetVariableNode.cs.meta | 11 + .../GraphElements/UdonNodes/UdonNodeExtensions.cs | 164 ++ .../UdonNodes/UdonNodeExtensions.cs.meta | 3 + .../UI/GraphView/GraphElements/UdonPort.cs | 450 +++++ .../UI/GraphView/GraphElements/UdonPort.cs.meta | 11 + .../UI/GraphView/GraphElements/UdonStackNode.cs | 6 + .../GraphView/GraphElements/UdonStackNode.cs.meta | 11 + .../GraphElements/UdonVariablesBlackboard.cs | 122 ++ .../GraphElements/UdonVariablesBlackboard.cs.meta | 11 + .../UdonGraphProgram/UI/GraphView/Search.meta | 8 + .../UI/GraphView/Search/UdonFocusedSearchWindow.cs | 64 + .../Search/UdonFocusedSearchWindow.cs.meta | 11 + .../UI/GraphView/Search/UdonFullSearchWindow.cs | 113 ++ .../GraphView/Search/UdonFullSearchWindow.cs.meta | 11 + .../UI/GraphView/Search/UdonPortSearchWindow.cs | 124 ++ .../GraphView/Search/UdonPortSearchWindow.cs.meta | 11 + .../GraphView/Search/UdonRegistrySearchWindow.cs | 183 ++ .../Search/UdonRegistrySearchWindow.cs.meta | 11 + .../UI/GraphView/Search/UdonSearchManager.cs | 119 ++ .../UI/GraphView/Search/UdonSearchManager.cs.meta | 11 + .../UI/GraphView/Search/UdonSearchWindowBase.cs | 195 ++ .../GraphView/Search/UdonSearchWindowBase.cs.meta | 11 + .../UI/GraphView/Search/UdonVariableTypeWindow.cs | 52 + .../Search/UdonVariableTypeWindow.cs.meta | 11 + .../UdonGraphProgram/UI/GraphView/TypeExtension.cs | 29 + .../UI/GraphView/TypeExtension.cs.meta | 11 + .../UI/GraphView/UdonFieldFactory.cs | 180 ++ .../UI/GraphView/UdonFieldFactory.cs.meta | 11 + .../UdonGraphProgram/UI/GraphView/UdonGraph.cs | 1392 +++++++++++++ .../UI/GraphView/UdonGraph.cs.meta | 11 + .../UI/GraphView/UdonGraphElementData.cs | 29 + .../UI/GraphView/UdonGraphElementData.cs.meta | 11 + .../UI/GraphView/UdonGraphStatus.cs | 144 ++ .../UI/GraphView/UdonGraphStatus.cs.meta | 11 + .../UI/GraphView/UdonGraphViewSettings.cs | 58 + .../UI/GraphView/UdonGraphViewSettings.cs.meta | 11 + .../UI/GraphView/UdonGraphWindow.cs | 324 +++ .../UI/GraphView/UdonGraphWindow.cs.meta | 11 + .../UI/GraphView/UdonParameterField.cs | 58 + .../UI/GraphView/UdonParameterField.cs.meta | 11 + .../UI/GraphView/UdonParameterProperty.cs | 224 +++ .../UI/GraphView/UdonParameterProperty.cs.meta | 11 + .../UI/GraphView/UdonProgramSourceView.cs | 60 + .../UI/GraphView/UdonProgramSourceView.cs.meta | 11 + .../UI/GraphView/UdonWelcomeView.cs | 212 ++ .../UI/GraphView/UdonWelcomeView.cs.meta | 11 + .../UI/GraphView/VideoPlayerElement.cs | 200 ++ .../UI/GraphView/VideoPlayerElement.cs.meta | 11 + .../UdonGraphProgram/UI/UdonGraphExtensions.cs | 637 ++++++ .../UI/UdonGraphExtensions.cs.meta | 11 + .../UdonGraphProgram/UdonGraphProgramAsset.cs | 210 ++ .../UdonGraphProgram/UdonGraphProgramAsset.cs.meta | 11 + .../UdonGraphProgramAssetEditor.cs | 21 + .../UdonGraphProgramAssetEditor.cs.meta | 11 + .../Udon/Editor/ProgramSources/UdonProgram.meta | 8 + .../ProgramSources/UdonProgram/UdonProgramAsset.cs | 2080 ++++++++++++++++++++ .../UdonProgram/UdonProgramAsset.cs.meta | 11 + .../UdonProgram/UdonProgramAssetEditor.cs | 19 + .../UdonProgram/UdonProgramAssetEditor.cs.meta | 11 + 122 files changed, 10628 insertions(+) create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes/UdonProgramSourceNewMenuAttribute.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes/UdonProgramSourceNewMenuAttribute.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/SerializedUdonProgramAssetEditor.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/SerializedUdonProgramAssetEditor.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAsset.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAsset.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetEditor.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetEditor.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetImporter.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetImporter.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ByteField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ByteField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/CharField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/CharField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/DecimalField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/DecimalField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/LayerMaskField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/LayerMaskField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/QuaternionField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/QuaternionField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/SByteField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/SByteField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ShortField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ShortField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedIntegerField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedIntegerField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedLongField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedLongField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedShortField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedShortField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/VRCUrlField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/VRCUrlField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/GraphElementExtension.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/GraphElementExtension.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayEditor.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayEditor.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayInspector.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayInspector.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonComment.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonComment.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGraphElement.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGraphElement.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGroup.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGroup.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonMinimap.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonMinimap.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNode.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNode.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/GetOrSetProgramVariableNode.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/GetOrSetProgramVariableNode.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SendCustomEventNode.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SendCustomEventNode.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetReturnValueNode.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetReturnValueNode.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetVariableNode.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetVariableNode.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/UdonNodeExtensions.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/UdonNodeExtensions.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonPort.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonPort.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonStackNode.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonStackNode.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonVariablesBlackboard.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonVariablesBlackboard.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonFocusedSearchWindow.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonFocusedSearchWindow.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonFullSearchWindow.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonFullSearchWindow.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonPortSearchWindow.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonPortSearchWindow.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonRegistrySearchWindow.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonRegistrySearchWindow.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonSearchManager.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonSearchManager.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonSearchWindowBase.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonSearchWindowBase.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonVariableTypeWindow.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Search/UdonVariableTypeWindow.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/TypeExtension.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/TypeExtension.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonFieldFactory.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonFieldFactory.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraph.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraph.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraphElementData.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraphElementData.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraphStatus.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraphStatus.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraphViewSettings.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraphViewSettings.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraphWindow.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonGraphWindow.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonParameterField.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonParameterField.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonParameterProperty.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonParameterProperty.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonProgramSourceView.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonProgramSourceView.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonWelcomeView.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/UdonWelcomeView.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/VideoPlayerElement.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/VideoPlayerElement.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/UdonGraphExtensions.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/UdonGraphExtensions.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UdonGraphProgramAsset.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UdonGraphProgramAsset.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UdonGraphProgramAssetEditor.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UdonGraphProgramAssetEditor.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonProgram.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonProgram/UdonProgramAsset.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonProgram/UdonProgramAsset.cs.meta create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonProgram/UdonProgramAssetEditor.cs create mode 100644 VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonProgram/UdonProgramAssetEditor.cs.meta (limited to 'VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources') diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes.meta new file mode 100644 index 00000000..1e05c23e --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 564cb755fc823d94d98948f3bb3f95cd +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes/UdonProgramSourceNewMenuAttribute.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes/UdonProgramSourceNewMenuAttribute.cs new file mode 100644 index 00000000..17be4606 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes/UdonProgramSourceNewMenuAttribute.cs @@ -0,0 +1,18 @@ +using System; + +namespace VRC.Udon.Editor.ProgramSources.Attributes +{ + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public class UdonProgramSourceNewMenuAttribute : Attribute + { + public Type Type { get; } + public string DisplayName { get; } + + public UdonProgramSourceNewMenuAttribute(Type type, string displayName) + { + Type = type; + DisplayName = displayName; + } + } +} + diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes/UdonProgramSourceNewMenuAttribute.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes/UdonProgramSourceNewMenuAttribute.cs.meta new file mode 100644 index 00000000..ea45c1be --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/Attributes/UdonProgramSourceNewMenuAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0e5ced9511d591140b191bbd9e948e61 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/SerializedUdonProgramAssetEditor.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/SerializedUdonProgramAssetEditor.cs new file mode 100644 index 00000000..33ecd07f --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/SerializedUdonProgramAssetEditor.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using UnityEditor; +using VRC.Udon.Common.Interfaces; +using VRC.Udon.ProgramSources; +using VRC.Udon.Serialization.OdinSerializer; + +namespace VRC.Udon.Editor.ProgramSources +{ + [CustomEditor(typeof(SerializedUdonProgramAsset))] + public class SerializedUdonProgramAssetEditor : UnityEditor.Editor + { + private SerializedProperty _serializedProgramBytesStringSerializedProperty; + private SerializedProperty _serializationDataFormatSerializedProperty; + + private void OnEnable() + { + _serializedProgramBytesStringSerializedProperty = serializedObject.FindProperty("serializedProgramBytesString"); + _serializationDataFormatSerializedProperty = serializedObject.FindProperty("serializationDataFormat"); + } + + public override void OnInspectorGUI() + { + DrawSerializationDebug(); + } + + [Conditional("UDON_DEBUG")] + private void DrawSerializationDebug() + { + EditorGUILayout.LabelField($"DataFormat: {(DataFormat)_serializationDataFormatSerializedProperty.enumValueIndex}"); + + if(string.IsNullOrEmpty(_serializedProgramBytesStringSerializedProperty.stringValue)) + { + return; + } + + if(_serializationDataFormatSerializedProperty.enumValueIndex == (int)DataFormat.JSON) + { + using(new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.TextArea(System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(_serializedProgramBytesStringSerializedProperty.stringValue))); + } + } + else + { + using(new EditorGUI.DisabledScope(true)) + { + SerializedUdonProgramAsset serializedUdonProgramAsset = (SerializedUdonProgramAsset)target; + IUdonProgram udonProgram = serializedUdonProgramAsset.RetrieveProgram(); + byte[] serializedBytes = SerializationUtility.SerializeValue(udonProgram, DataFormat.JSON, out List _); + EditorGUILayout.TextArea(System.Text.Encoding.UTF8.GetString(serializedBytes)); + } + } + } + } +} diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/SerializedUdonProgramAssetEditor.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/SerializedUdonProgramAssetEditor.cs.meta new file mode 100644 index 00000000..e72c03a7 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/SerializedUdonProgramAssetEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: e1b5b45f24b268b42826fc5c5497dc15 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram.meta new file mode 100644 index 00000000..6fccff45 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2811cc384b684c04f9b647c597b55ff8 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAsset.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAsset.cs new file mode 100644 index 00000000..0045931e --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAsset.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using UnityEditor; +using UnityEngine; +using VRC.Udon.Editor; +using VRC.Udon.Editor.ProgramSources; +using VRC.Udon.Editor.ProgramSources.Attributes; + +[assembly: UdonProgramSourceNewMenu(typeof(UdonAssemblyProgramAsset), "Udon Assembly Program Asset")] + +namespace VRC.Udon.Editor.ProgramSources +{ + [CreateAssetMenu(menuName = "VRChat/Udon/Udon Assembly Program Asset", fileName = "New Udon Assembly Program Asset")] + public class UdonAssemblyProgramAsset : UdonProgramAsset + { + [SerializeField] + protected string udonAssembly = ""; + + [SerializeField] + protected string assemblyError = null; + + public delegate void AssembleDelegate(bool success, string assembly); + public event AssembleDelegate OnAssemble; + + protected override void DrawProgramSourceGUI(UdonBehaviour udonBehaviour, ref bool dirty) + { + DrawAssemblyTextArea(!Application.isPlaying, ref dirty); + DrawAssemblyErrorTextArea(); + + base.DrawProgramSourceGUI(udonBehaviour, ref dirty); + } + + protected override void RefreshProgramImpl() + { + AssembleProgram(); + } + + [PublicAPI] + protected virtual void DrawAssemblyTextArea(bool allowEditing, ref bool dirty) + { + EditorGUILayout.LabelField("Assembly Code", EditorStyles.boldLabel); + if(GUILayout.Button("Copy Assembly To Clipboard")) + { + EditorGUIUtility.systemCopyBuffer = udonAssembly; + } + + EditorGUI.BeginChangeCheck(); + using(new EditorGUI.DisabledScope(!allowEditing)) + { + string newAssembly = EditorGUILayout.TextArea(udonAssembly); + if(EditorGUI.EndChangeCheck()) + { + dirty = true; + Undo.RecordObject(this, "Edit Assembly Program Code"); + udonAssembly = newAssembly; + UdonEditorManager.Instance.QueueAndRefreshProgram(this); + } + } + } + + [PublicAPI] + protected void DrawAssemblyErrorTextArea() + { + if(string.IsNullOrEmpty(assemblyError)) + { + return; + } + + EditorGUILayout.LabelField("Assembly Error", EditorStyles.boldLabel); + using(new EditorGUI.DisabledScope(true)) + { + EditorGUILayout.TextArea(assemblyError); + } + } + + [PublicAPI] + protected void AssembleProgram() + { + try + { + program = UdonEditorManager.Instance.Assemble(udonAssembly); + assemblyError = null; + OnAssemble?.Invoke(true, udonAssembly); + } + catch(Exception e) + { + program = null; + assemblyError = e.Message; + Debug.LogException(e); + OnAssemble?.Invoke(false, assemblyError); + } + } + + } +} diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAsset.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAsset.cs.meta new file mode 100644 index 00000000..c2d8a2b6 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAsset.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 22203902d63dec94194fefc3e155c43b +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetEditor.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetEditor.cs new file mode 100644 index 00000000..a6b6c856 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetEditor.cs @@ -0,0 +1,9 @@ +using UnityEditor; + +namespace VRC.Udon.Editor.ProgramSources +{ + [CustomEditor(typeof(UdonAssemblyProgramAsset))] + public class UdonAssemblyProgramAssetEditor : UdonProgramAssetEditor + { + } +} diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetEditor.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetEditor.cs.meta new file mode 100644 index 00000000..e7fb7fee --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3df823f3ab561fc43bcb81286e14b91d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetImporter.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetImporter.cs new file mode 100644 index 00000000..409c2c68 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetImporter.cs @@ -0,0 +1,27 @@ +using System.IO; +using JetBrains.Annotations; +using UnityEditor; +using UnityEditor.Experimental.AssetImporters; +using UnityEngine; + +namespace VRC.Udon.Editor.ProgramSources +{ + [ScriptedImporter(1, "uasm")] + [UsedImplicitly] + public class UdonAssemblyProgramAssetImporter : ScriptedImporter + { + public override void OnImportAsset(AssetImportContext ctx) + { + UdonAssemblyProgramAsset udonAssemblyProgramAsset = ScriptableObject.CreateInstance(); + SerializedObject serializedUdonAssemblyProgramAsset = new SerializedObject(udonAssemblyProgramAsset); + SerializedProperty udonAssemblyProperty = serializedUdonAssemblyProgramAsset.FindProperty("udonAssembly"); + udonAssemblyProperty.stringValue = File.ReadAllText(ctx.assetPath); + serializedUdonAssemblyProgramAsset.ApplyModifiedProperties(); + + udonAssemblyProgramAsset.RefreshProgram(); + + ctx.AddObjectToAsset("Imported Udon Assembly Program", udonAssemblyProgramAsset); + ctx.SetMainObject(udonAssemblyProgramAsset); + } + } +} diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetImporter.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetImporter.cs.meta new file mode 100644 index 00000000..f3951da2 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonAssemblyProgram/UdonAssemblyProgramAssetImporter.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3c0638314c289c24193b47d1c53c9fca +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram.meta new file mode 100644 index 00000000..1f5f980a --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fc78ce0a8f47f2642a2ed5fd39f05017 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI.meta new file mode 100644 index 00000000..61c37e70 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d162e94e3ec124e4398f173057d3715b +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView.meta new file mode 100644 index 00000000..38782780 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 18fcefe274099824baeb479f629c1999 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields.meta new file mode 100644 index 00000000..70a6e016 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3963ddfd2d404d449ab36d09da1a92bc +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ByteField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ByteField.cs new file mode 100644 index 00000000..76ab6a34 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ByteField.cs @@ -0,0 +1,24 @@ +using System; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class ByteField : BaseField + { + public ByteField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Char Editor and listen for changes + IntegerField field = new IntegerField(); + + field.RegisterValueChangedCallback( + e => + value = Convert.ToByte(e.newValue)); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ByteField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ByteField.cs.meta new file mode 100644 index 00000000..06d12e3c --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ByteField.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c66f97d5a5a38cb478fd4df11ece7be7 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/CharField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/CharField.cs new file mode 100644 index 00000000..1850cbfc --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/CharField.cs @@ -0,0 +1,24 @@ +using UnityEngine.UIElements; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class CharField : BaseField + { + public CharField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Char Editor and listen for changes + TextField field = new TextField + { + maxLength = 1 + }; + field.RegisterValueChangedCallback( + e => + value = e.newValue.ToCharArray()[0]); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/CharField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/CharField.cs.meta new file mode 100644 index 00000000..f4388e8c --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/CharField.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 602ffcf431b3e4f41a18bd868751439a +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/DecimalField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/DecimalField.cs new file mode 100644 index 00000000..d5d708b0 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/DecimalField.cs @@ -0,0 +1,23 @@ +using System; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class DecimalField : BaseField + { + public DecimalField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Char Editor and listen for changes + DoubleField field = new DoubleField(); + field.RegisterValueChangedCallback( + e => + value = Convert.ToDecimal(e.newValue)); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/DecimalField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/DecimalField.cs.meta new file mode 100644 index 00000000..feae7a68 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/DecimalField.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e79144dad56140a7bcd0d9f945153784 +timeCreated: 1632419615 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/LayerMaskField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/LayerMaskField.cs new file mode 100644 index 00000000..51349917 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/LayerMaskField.cs @@ -0,0 +1,24 @@ +using UnityEngine.UIElements; +using UIElements = UnityEditor.UIElements; +using UnityEngine; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class LayerMaskField : BaseField + { + public LayerMaskField() : base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create LayerMask Editor and listen for changes + UIElements.LayerMaskField field = new UIElements.LayerMaskField(); + field.RegisterValueChangedCallback(e => + { + this.value = e.newValue; + }); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/LayerMaskField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/LayerMaskField.cs.meta new file mode 100644 index 00000000..67438a23 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/LayerMaskField.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 42d9183d7c7ce67448d1e010456e36f9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/QuaternionField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/QuaternionField.cs new file mode 100644 index 00000000..13561b7c --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/QuaternionField.cs @@ -0,0 +1,24 @@ +using UnityEngine.UIElements; +using UnityEditor.UIElements; +using UnityEngine; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class QuaternionField : BaseField + { + public QuaternionField() :base(null, null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Vector4 Editor and listen for changes + Vector4Field field = new Vector4Field(); + field.RegisterValueChangedCallback( + e => + value = new Quaternion(e.newValue.x, e.newValue.y, e.newValue.z, e.newValue.w) + ); + Add(field); + } + + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/QuaternionField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/QuaternionField.cs.meta new file mode 100644 index 00000000..fefc9cf3 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/QuaternionField.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1c96407d2b7698c4c8a0476efa2c765d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/SByteField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/SByteField.cs new file mode 100644 index 00000000..f0fa54df --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/SByteField.cs @@ -0,0 +1,23 @@ +using System; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class SByteField : BaseField + { + public SByteField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Char Editor and listen for changes + IntegerField field = new IntegerField(); + field.RegisterValueChangedCallback( + e => + value = Convert.ToSByte(e.newValue)); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/SByteField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/SByteField.cs.meta new file mode 100644 index 00000000..2e4769b0 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/SByteField.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 42747856e1884be6b1112c8838963662 +timeCreated: 1632419007 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ShortField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ShortField.cs new file mode 100644 index 00000000..9d3a1140 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ShortField.cs @@ -0,0 +1,23 @@ +using System; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class ShortField : BaseField + { + public ShortField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Char Editor and listen for changes + IntegerField field = new IntegerField(); + field.RegisterValueChangedCallback( + e => + value = Convert.ToInt16(e.newValue)); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ShortField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ShortField.cs.meta new file mode 100644 index 00000000..72da7dfd --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/ShortField.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: bcda1561abdb40c69f9eeb9211bd3e3d +timeCreated: 1632419462 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedIntegerField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedIntegerField.cs new file mode 100644 index 00000000..77f5d696 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedIntegerField.cs @@ -0,0 +1,23 @@ +using System; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class UnsignedIntegerField : BaseField + { + public UnsignedIntegerField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Char Editor and listen for changes + IntegerField field = new IntegerField(); + field.RegisterValueChangedCallback( + e => + value = Convert.ToUInt32(e.newValue)); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedIntegerField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedIntegerField.cs.meta new file mode 100644 index 00000000..516eafbb --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedIntegerField.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 0b91b14ff1e24276863f173d0e9c760c +timeCreated: 1632419145 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedLongField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedLongField.cs new file mode 100644 index 00000000..81298eb1 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedLongField.cs @@ -0,0 +1,23 @@ +using System; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class UnsignedLongField : BaseField + { + public UnsignedLongField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Char Editor and listen for changes + IntegerField field = new IntegerField(); + field.RegisterValueChangedCallback( + e => + value = Convert.ToUInt64(e.newValue)); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedLongField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedLongField.cs.meta new file mode 100644 index 00000000..653f1a3b --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedLongField.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1d1c8af690a94ef0a670e5d321733414 +timeCreated: 1632419341 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedShortField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedShortField.cs new file mode 100644 index 00000000..6eac945f --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedShortField.cs @@ -0,0 +1,23 @@ +using System; +using UnityEditor.UIElements; +using UnityEngine.UIElements; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class UnsignedShortField : BaseField + { + public UnsignedShortField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Char Editor and listen for changes + IntegerField field = new IntegerField(); + field.RegisterValueChangedCallback( + e => + value = Convert.ToUInt16(e.newValue)); + + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedShortField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedShortField.cs.meta new file mode 100644 index 00000000..058ae560 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/UnsignedShortField.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 1387a4616a8f4c87bd0d55d2ffc021c8 +timeCreated: 1632419528 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/VRCUrlField.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/VRCUrlField.cs new file mode 100644 index 00000000..f6fb8307 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/VRCUrlField.cs @@ -0,0 +1,23 @@ +using UnityEngine.UIElements; +using System; +using VRC.SDKBase; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI +{ + public class VRCUrlField : BaseField + { + public VRCUrlField():base(null,null) + { + // Set up styling + AddToClassList("UdonValueField"); + + // Create Text Editor and listen for changes + TextField field = new TextField(50, false, false, Char.MinValue); + field.RegisterValueChangedCallback( + e => + value = new VRCUrl(e.newValue) + ); + Add(field); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/VRCUrlField.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/VRCUrlField.cs.meta new file mode 100644 index 00000000..28d6b842 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/Fields/VRCUrlField.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: eeb751ae1c234a04291c5039626f3470 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements.meta new file mode 100644 index 00000000..4c7d4a8f --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: efe54a45d15688542911081f5876ca68 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/GraphElementExtension.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/GraphElementExtension.cs new file mode 100644 index 00000000..55179e41 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/GraphElementExtension.cs @@ -0,0 +1,81 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEngine.UIElements; +#else +using UnityEngine.Experimental.UIElements; +#endif +using System; +using UnityEditor.SceneManagement; +using UnityEngine; +using VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView; + +#if UNITY_2019_3_OR_NEWER +namespace UnityEditor.Experimental.GraphView +#else +namespace UnityEditor.Experimental.UIElements.GraphView +#endif +{ + public static class GraphElementExtension + { + + public static void Reload(this GraphElement element) + { + var evt = new Event() + { + type = EventType.ExecuteCommand, + commandName = UdonGraphCommands.Reload + }; + using (var e = ExecuteCommandEvent.GetPooled(evt)) + { + element.SendEvent(e); + } + } + + public static void Compile(this GraphElement element) + { + var evt = new Event() + { + type = EventType.ExecuteCommand, + commandName = UdonGraphCommands.Compile + }; + using (var e = ExecuteCommandEvent.GetPooled(evt)) + { + element.SendEvent(e); + } + } + + public static string GetUid(this GraphElement element) + { +#if UNITY_2019_3_OR_NEWER + return element.viewDataKey; +#else + return element.persistenceKey; +#endif + } + + public static void MarkDirty() + { + if (!EditorApplication.isPlaying) + { + EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene()); + } + } + + public static Vector2 GetSnappedPosition(Vector2 position) + { + // don't snap at 0 size + var snap = Settings.GridSnapSize; + if (snap == 0) return position; + + position.x = (float)Math.Round(position.x / snap) * snap; + position.y = (float)Math.Round(position.y / snap) * snap; + + return position; + } + + public static Rect GetSnappedRect(Rect rect) + { + rect.position = GetSnappedPosition(rect.position); + return rect; + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/GraphElementExtension.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/GraphElementExtension.cs.meta new file mode 100644 index 00000000..ebc4db20 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/GraphElementExtension.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 469db50616185d04e8a46dcd75db12d2 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayEditor.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayEditor.cs new file mode 100644 index 00000000..437334c0 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayEditor.cs @@ -0,0 +1,86 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEngine.UIElements; +#else +using UnityEngine.Experimental.UIElements; +#endif +using System; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonArrayEditor : VisualElement + { + private IArrayProvider _inspector; + private Button _editArrayButton; + private Action _setValueCallback; + private Type _type; + private object _value; + private bool _inspectorOpen = false; + + public UdonArrayEditor(Type t, Action valueChangedAction, object value) + { + _setValueCallback = valueChangedAction; + _value = value; + _type = t.GetElementType(); + + _editArrayButton = new Button(EditArray) + { + text = "Edit", + name = "array-editor", + }; + + Add(_editArrayButton); + } + + private void EditArray() + { + if (_inspector == null) + { + // Create it new + Type typedArrayInspector = (typeof(UdonArrayInspector<>)).MakeGenericType(_type); + _inspector = (Activator.CreateInstance(typedArrayInspector, null, _value) as IArrayProvider); + + AddInspector(); + _inspectorOpen = true; + _editArrayButton.text = "Save"; + return; + } + else + { + // Update Values when 'Save' is clicked + if(_inspectorOpen) + { + // Update Values + var values = _inspector.GetValues(); + _setValueCallback(values); + + // Remove Inspector + _inspector.RemoveFromHierarchy(); + + // Update Button Text + _editArrayButton.text = "Edit"; + _inspectorOpen = false; + return; + } + else + { + // Inspector exists, it's just removed + _inspectorOpen = true; + AddInspector(); + _editArrayButton.text = "Save"; + } + } + } + + private void AddInspector() + { + if (parent.GetType() == typeof(UdonPort)) + { + parent.parent.Add(_inspector as VisualElement); + } + else + { + Add(_inspector as VisualElement); + } + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayEditor.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayEditor.cs.meta new file mode 100644 index 00000000..135a415d --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayEditor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f257a6eeae213a4db991d486cace003 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayInspector.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayInspector.cs new file mode 100644 index 00000000..446950cc --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayInspector.cs @@ -0,0 +1,156 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEngine.UIElements; +using UnityEditor.UIElements; +#else +using UnityEngine.Experimental.UIElements; +using UnityEditor.Experimental.UIElements; +#endif +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonArrayInspector : VisualElement, IArrayProvider + { + private ScrollView _scroller; + private List _fields = new List(); + private IntegerField _sizeField; + private Action _setValueCallback; + + public UdonArrayInspector(Action valueChangedAction, object value) + { + _setValueCallback = valueChangedAction; + + AddToClassList("input-inspector"); + var resizeContainer = new VisualElement() + { + name = "resize-container", + }; + resizeContainer.Add(new Label("size")); + + _sizeField = new IntegerField(); + _sizeField.isDelayed = true; + #if UNITY_2019_3_OR_NEWER + _sizeField.RegisterValueChangedCallback((evt) => + #else + _sizeField.OnValueChanged((evt) => + #endif + { + ResizeTo(evt.newValue); + }); + resizeContainer.Add(_sizeField); + Add(resizeContainer); + + _scroller = new ScrollView() + { + name = "array-scroll", + }; + Add(_scroller); + + if (value == null) + { + // Can't show if array is empty + _sizeField.value = 0; + return; + } + else + { + IEnumerable values = (value as IEnumerable); + if (values == null) + { + Debug.LogError($"Couldn't convert {value} to {typeof(T).ToString()} Array"); + return; + } + + // Populate fields and their values from passed-in array + _fields = new List(); + foreach (var item in values) + { + var field = GetValueField(item); + _fields.Add(field); + + _scroller.contentContainer.Add(field); + } + + _sizeField.value = values.Count(); + } + + } + + private void ResizeTo(int newValue) + { + _sizeField.value = newValue; + + // Create from scratch if currentFields are null + if(_fields == null) + { + Debug.Log($"Creating from Scratch"); + _fields = new List(); + for (int i = 0; i < newValue; i++) + { + var field = GetValueField(null); + _fields.Add(field); + _scroller.contentContainer.Add(field as VisualElement); + } + return; + } + + // Shrink list if new value is less than old one + if(newValue < _fields.Count) + { + for (int i = _fields.Count - 1; i >= newValue; i--) + { + (_fields[i] as VisualElement).RemoveFromHierarchy(); + _fields.RemoveAt(i); + } + MarkDirtyRepaint(); + return; + } + + // Expand list if new value is more than old one. + if(newValue > _fields.Count) + { + int numberToAdd = newValue - _fields.Count; + for (int i = 0; i < numberToAdd; i++) + { + var field = GetValueField(null); + if (field == null) + { + Debug.LogWarning($"Sorry, can't edit object of type {typeof(T).ToString()} yet."); + return; + } + _fields.Add(field); + + _scroller.contentContainer.Add(field as VisualElement); + } + MarkDirtyRepaint(); + return; + } + } + + private VisualElement GetValueField(object value) + { + return UdonFieldFactory.CreateField(typeof(T), value, _setValueCallback); + } + + public object GetValues() + { + var result = new List(); + for (int i = 0; i < _fields.Count; i++) + { + var f = (_fields[i] as INotifyValueChanged); + result.Add(f.value); + } + return result.ToArray(); + } + + } + + public interface IArrayProvider + { + object GetValues(); + void RemoveFromHierarchy(); // in VisualElement + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayInspector.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayInspector.cs.meta new file mode 100644 index 00000000..1a535cb2 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonArrayInspector.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: f4f0ade55ae13b6468a765826f1f2540 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonComment.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonComment.cs new file mode 100644 index 00000000..78ff9926 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonComment.cs @@ -0,0 +1,220 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +using UnityEngine.UIElements; +using UnityEditor.UIElements; +using UnityEngine.UIElements.StyleSheets; +#else +using UnityEditor.Experimental.UIElements.GraphView; +using UnityEngine.Experimental.UIElements; +using UnityEngine.Experimental.UIElements.StyleSheets; +#endif +using System; +using UnityEditor; +using UnityEngine; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonComment : UdonGraphElement, IUdonGraphElementDataProvider + { + private VisualElement _mainContainer; + private Label _label; + private TextField _textField; + private CustomData _customData = new CustomData(); + private UdonGraph _graph; + public UdonGroup group; + + // Called from Context menu and Reload + public static UdonComment Create(string value, Rect position, UdonGraph graph) + { + var comment = new UdonComment("", graph); + + // make sure rect size is not 0 + position.width = position.width > 0 ? position.width : 128; + position.height = position.height > 0 ? position.height : 40; + + comment._customData.layout = position; + comment._customData.title = value; + + comment.UpdateFromData(); + graph.MarkSceneDirty(); + + return comment; + } + + public static UdonComment Create(UdonGraphElementData elementData, UdonGraph graph) + { + var comment = new UdonComment(elementData.jsonData, graph); + + comment.UpdateFromData(); + graph.MarkSceneDirty(); + + return comment; + } + + private UdonComment(string jsonData, UdonGraph graph) + { + title = "Comment"; + name = "comment"; + _graph = graph; + + capabilities |= Capabilities.Selectable | Capabilities.Movable | Capabilities.Deletable | + Capabilities.Resizable; + pickingMode = PickingMode.Ignore; + + type = UdonGraphElementType.UdonComment; + + if(!string.IsNullOrEmpty(jsonData)) + { + EditorJsonUtility.FromJsonOverwrite(jsonData, _customData); + } + + _mainContainer = new VisualElement(); + _mainContainer.StretchToParentSize(); + _mainContainer.AddToClassList("mainContainer"); + Add(_mainContainer); + + _label = new Label(); + _label.RegisterCallback(OnLabelClick); + _mainContainer.Add(_label); + + _textField = new TextField(1000, true, false, '*'); + _textField.isDelayed = true; + + // Support IME + _textField.RegisterCallback(evt =>{ Input.imeCompositionMode = IMECompositionMode.On;}); + _textField.RegisterCallback(evt => + { + SetText(_textField.text); + Input.imeCompositionMode = IMECompositionMode.Auto; + SwitchToEditMode(false); + }); + +#if UNITY_2019_3_OR_NEWER + _textField.RegisterValueChangedCallback((evt) => +#else + _textField.OnValueChanged((evt) => +#endif + { + SetText(evt.newValue); + SwitchToEditMode(false); + }); + } + + private void SaveNewData() + { + _graph.SaveGraphElementData(this); + } + + private void UpdateFromData() + { + if(_customData != null) + { + layer = _customData.layer; + if(string.IsNullOrEmpty(_customData.uid)) + { + _customData.uid = Guid.NewGuid().ToString(); + } + + uid = _customData.uid; + + SetPosition(_customData.layout); + SetText(_customData.title); + } + } +#if UNITY_2019_3_OR_NEWER + protected override void OnCustomStyleResolved(ICustomStyle style) + { + base.OnCustomStyleResolved(style); +#else + protected override void OnStyleResolved(ICustomStyle style) + { + base.OnStyleResolved(style); +#endif + // Something is forcing style! Resetting a few things here, grrr. + + this.style.borderBottomWidth = 1; + + var resizer = this.Q(null, "resizer"); + if(resizer != null) + { + resizer.style.paddingTop = 0; + resizer.style.paddingLeft = 0; + } + } + + public override void SetPosition(Rect newPos) + { + newPos = GraphElementExtension.GetSnappedRect(newPos); + base.SetPosition(newPos); + } + + public override void UpdatePresenterPosition() + { + base.UpdatePresenterPosition(); + _customData.layout = GraphElementExtension.GetSnappedRect(GetPosition()); + SaveNewData(); + if (group != null) + { + group.SaveNewData(); + } + } + + private double lastClickTime; + private const double doubleClickSpeed = 0.5; + + private void OnLabelClick(MouseDownEvent evt) + { + var newTime = EditorApplication.timeSinceStartup; + if(newTime - lastClickTime < doubleClickSpeed) + { + SwitchToEditMode(true); + } + + lastClickTime = newTime; + } + + private void SwitchToEditMode(bool switchingToEdit) + { + if (switchingToEdit) + { + _mainContainer.Remove(_label); + _textField.value = _label.text; + _mainContainer.Add(_textField); + _textField.delegatesFocus = true; + _textField.Focus(); + } + else + { + _mainContainer.Remove(_textField); + _mainContainer.Add(_label); + } + + MarkDirtyRepaint(); + } + + public void SetText(string value) + { + Undo.RecordObject(_graph.graphProgramAsset, "Rename Comment"); + value = value.TrimEnd(); + _customData.title = value; + _label.text = value; + SaveNewData(); + MarkDirtyRepaint(); + } + + public UdonGraphElementData GetData() + { + return new UdonGraphElementData(UdonGraphElementType.UdonComment, uid, + EditorJsonUtility.ToJson(_customData)); + } + + public class CustomData + { + public string uid; + public Rect layout; + public string title = "Comment"; + public int layer; + public Color elementTypeColor; + } + } +} diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonComment.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonComment.cs.meta new file mode 100644 index 00000000..2840e341 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonComment.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7e5916b8dd19e4445a9156a457b82ee4 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGraphElement.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGraphElement.cs new file mode 100644 index 00000000..a6419359 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGraphElement.cs @@ -0,0 +1,48 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +#else +using UnityEditor.Experimental.UIElements.GraphView; +#endif +using System; +using UnityEngine; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonGraphElement : GraphElement + { +#if UNITY_2019_3_OR_NEWER + public string uid { get => viewDataKey; set => viewDataKey = value; } +#else + public string uid { get => persistenceKey; set => persistenceKey = value; } +#endif + internal UdonGraphElementType type = UdonGraphElementType.GraphElement; + + internal UdonGraphElement() + { + } + } + + public interface IUdonGraphElementDataProvider + { + UdonGraphElementData GetData(); + } + + [Serializable] + public class GraphRect + { + public float x; + public float y; + public float width; + public float height; + + public GraphRect(Rect input) + { + this.x = Mathf.Round(input.x); + this.y = Mathf.Round(input.y); + this.width = Mathf.Round(input.width); + this.height = Mathf.Round(input.height); + } + + public Rect rect => new Rect(this.x, this.y, this.width, this.height); + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGraphElement.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGraphElement.cs.meta new file mode 100644 index 00000000..1137de20 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGraphElement.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ba3ecc4c46929404d8c2ec920743b823 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGroup.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGroup.cs new file mode 100644 index 00000000..d6c91a73 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGroup.cs @@ -0,0 +1,213 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +using UnityEngine.UIElements; +#else +using UnityEditor.Experimental.UIElements.GraphView; +using UnityEngine.Experimental.UIElements; +#endif +using System; +using System.Collections.Generic; +using UnityEditor; +using UnityEngine; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonGroup : Group, IUdonGraphElementDataProvider + { + public string uid { get => _uid; set => _uid = value; } + private CustomData _customData = new CustomData(); + private UdonGraph _graph; + private string _uid; + private const int GROUP_LAYER = -1; + + public static UdonGroup Create(string value, Rect position, UdonGraph graph) + { + var group = new UdonGroup("", graph); + + group.uid = Guid.NewGuid().ToString(); + + // make sure rect size is not 0 + position.width = position.width > 0 ? position.width : 128; + position.height = position.height > 0 ? position.height : 128; + + group._customData.uid = group.uid; + group._customData.layout = position; + group._customData.title = value; + + return group; + } + + // Called in Reload > RestoreElementFromData + public static UdonGroup Create(UdonGraphElementData elementData, UdonGraph graph) + { + return new UdonGroup(elementData.jsonData, graph); + } + + // current order of operations issue when creating a group from the context menu means this isn't set until first save. This allows us to force it. + public void UpdateDataId() + { + _customData.uid = uid; + } + + // Build a Group from jsonData, save to userData + private UdonGroup(string jsonData, UdonGraph graph) + { + title = "Group"; + _graph = graph; + layer = GROUP_LAYER; + + if (!string.IsNullOrEmpty(jsonData)) + { + EditorJsonUtility.FromJsonOverwrite(jsonData, _customData); + } + + // listen for changes on child elements + RegisterCallback(OnGeometryChanged); + } + + private void OnGeometryChanged(GeometryChangedEvent evt) + { + _customData.layout = GraphElementExtension.GetSnappedRect(GetPosition()); + } + + public void Initialize() + { + if (_customData != null) + { + // Propagate data to useful places + title = _customData.title; + layer = _customData.layer; + if (string.IsNullOrEmpty(_customData.uid)) + { + _customData.uid = Guid.NewGuid().ToString(); + } + + uid = _customData.uid; + + // Add all elements from graph to self + var childUIDs = _customData.containedElements; + if (childUIDs.Count > 0) + { + foreach (var item in childUIDs) + { + GraphElement element = _graph.GetElementByGuid(item); + if (element != null) + { + if (ContainsElement(element)) continue; + AddElement(element); + if (element is UdonComment c) + { + c.group = this; + } + else if (element is UdonNode n) + { + n.group = this; + } + } + } + } + else + { + // No children, so restore the saved position + SetPosition(_customData.layout); + } + } + } + + public override void SetPosition(Rect newPos) + { + newPos = GraphElementExtension.GetSnappedRect(newPos); + base.SetPosition(newPos); + } + + public void SaveNewData() + { + _graph.SaveGraphElementData(this); + } + + // Save data to asset after new position set + public override void UpdatePresenterPosition() + { + base.UpdatePresenterPosition(); + Rect layout = GraphElementExtension.GetSnappedRect(GetPosition()); + base.SetPosition(layout); + SaveNewData(); + } + + // Save data to asset after rename + protected override void OnGroupRenamed(string oldName, string newName) + { + // limit name to 100 characters + title = newName.Substring(0, Mathf.Min(newName.Length, 100)); + _customData.title = title; + SaveNewData(); + } + + protected override void OnElementsAdded(IEnumerable elements) + { + base.OnElementsAdded(elements); + foreach (var element in elements) + { + if (!_customData.containedElements.Contains(element.GetUid())) + { + _customData.containedElements.Add(element.GetUid()); + } + + // Set group variable on UdonNodes + if (element is UdonNode) + { + (element as UdonNode).group = this; + element.BringToFront(); + } + + if (element is UdonComment) + { + (element as UdonComment).group = this; + } + } + SaveNewData(); + } + + protected override void OnElementsRemoved(IEnumerable elements) + { + base.OnElementsRemoved(elements); + foreach (var element in elements) + { + if (_customData.containedElements.Contains(element.GetUid())) + { + _customData.containedElements.Remove(element.GetUid()); + if (element is UdonNode) + { + (element as UdonNode).group = null; + } + else if (element is UdonComment) + { + (element as UdonComment).group = null; + } + } + } + + SaveNewData(); + } + + public override bool AcceptsElement(GraphElement element, ref string reasonWhyNotAccepted) + { + return base.AcceptsElement(element, ref reasonWhyNotAccepted); + } + + public UdonGraphElementData GetData() + { + return new UdonGraphElementData(UdonGraphElementType.UdonGroup, uid, EditorJsonUtility.ToJson(_customData)); + } + + public class CustomData + { + public string uid; + public Rect layout; + public List containedElements = new List(); + public string title; + public int layer; + public Color elementTypeColor; + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGroup.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGroup.cs.meta new file mode 100644 index 00000000..291451b5 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonGroup.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1b8045222a10ce04b815642b9cd5ca17 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonMinimap.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonMinimap.cs new file mode 100644 index 00000000..c6fec3e9 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonMinimap.cs @@ -0,0 +1,57 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +#else +using UnityEditor.Experimental.UIElements.GraphView; +#endif +using UnityEngine; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonMinimap : MiniMap, IUdonGraphElementDataProvider + { + private CustomData _customData = new CustomData(); + private UdonGraph _graph; + + public UdonMinimap(UdonGraph graph) + { + _graph = graph; + + name = "UdonMap"; + maxWidth = 200; + maxHeight = 100; + anchored = false; + SetPosition(_customData.layout); + } + + public void SetVisible(bool value) + { + visible = value; + _customData.visible = value; + _graph.SaveGraphElementData(this); + } + + public override void UpdatePresenterPosition() + { + _customData.layout = GetPosition(); + _graph.SaveGraphElementData(this); + } + + public UdonGraphElementData GetData() + { + return new UdonGraphElementData(UdonGraphElementType.Minimap, this.GetUid(), JsonUtility.ToJson(_customData)); + } + + internal void LoadData(UdonGraphElementData data) + { + JsonUtility.FromJsonOverwrite(data.jsonData, _customData); + SetPosition(_customData.layout); + visible = _customData.visible; + } + + public class CustomData + { + public bool visible = true; + public Rect layout = new Rect(new Vector2(10, 20), Vector2.zero); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonMinimap.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonMinimap.cs.meta new file mode 100644 index 00000000..dc27107b --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonMinimap.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b006d67642298f04e895b6709ef12429 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNode.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNode.cs new file mode 100644 index 00000000..c690b6af --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNode.cs @@ -0,0 +1,1093 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +using EditorGV = UnityEditor.Experimental.GraphView; +using EngineUI = UnityEngine.UIElements; +using EditorUI = UnityEditor.UIElements; +using UnityEngine.UIElements; +#else +using UnityEditor.Experimental.UIElements.GraphView; +using EditorGV = UnityEditor.Experimental.UIElements.GraphView; +using EngineUI = UnityEngine.Experimental.UIElements; +using EditorUI = UnityEditor.Experimental.UIElements; +using UnityEngine.Experimental.UIElements; +#endif +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEditor; +using UnityEngine; +using VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView.UdonNodes; +using VRC.Udon.Graph; +using VRC.Udon.Graph.Interfaces; +using VRC.Udon.Serialization; +using VRC.Udon.Serialization.OdinSerializer.Utilities; +using Random = UnityEngine.Random; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonNode : Node, IEdgeConnectorListener + { + // name is inherited from parent VisualElement class + public Type type; + public GameObject gameObject; + protected UdonGraph _graphView; + private EditorUI.PopupField _popup; + public UdonNodeDefinition definition; + public UdonNodeData data; + public Dictionary portsIn; + public Dictionary portsOut; + public List portsFlowIn; + public List portsFlowOut; + private INodeRegistry _registry; + public UdonGroup group; + + // Overload handling + private IList overloadDefinitions; + + private readonly Dictionary _optionNameCache = + new Dictionary(); + + private readonly Dictionary _cleanerOptionNameCache = + new Dictionary(); + + + public bool IsVariableNode => _variableNodeType != VariableNodeType.None; + + public UdonGraph Graph + { + get => _graphView; + private set { } + } + + public INodeRegistry Registry + { + get => _registry; + private set { } + } + + private readonly string[] _specialFlows = + { + "Block", + "Branch", + "For", + "Foreach", + "While", + "Is_Valid", + }; + + protected static readonly Dictionary DefinitionToTypeLookup = new Dictionary() + { + {"VRCUdonCommonInterfacesIUdonEventReceiver.__GetProgramVariable__SystemString__SystemObject", typeof(GetOrSetProgramVariableNode)}, + {"VRCUdonCommonInterfacesIUdonEventReceiver.__SetProgramVariable__SystemString_SystemObject__SystemVoid", typeof(GetOrSetProgramVariableNode)}, + {"VRCUdonCommonInterfacesIUdonEventReceiver.__GetProgramVariableType__SystemString__SystemType", typeof(GetOrSetProgramVariableNode)}, + {"VRCUdonCommonInterfacesIUdonEventReceiver.__SendCustomEvent__SystemString__SystemVoid", typeof(SendCustomEventNode)}, + {"VRCUdonCommonInterfacesIUdonEventReceiver.__SendCustomEventDelayedSeconds__SystemString_SystemSingle_VRCUdonCommonEnumsEventTiming__SystemVoid", typeof(SendCustomEventNode)}, + {"VRCUdonCommonInterfacesIUdonEventReceiver.__SendCustomEventDelayedFrames__SystemString_SystemInt32_VRCUdonCommonEnumsEventTiming__SystemVoid", typeof(SendCustomEventNode)}, + {"VRCUdonCommonInterfacesIUdonEventReceiver.__SendCustomNetworkEvent__VRCUdonCommonInterfacesNetworkEventTarget_SystemString__SystemVoid", typeof(SendCustomEventNode)}, + {"Set_ReturnValue", typeof(SetReturnValueNode)}, + {"Set_Variable", typeof(SetVariableNode)}, + }; + +#if UNITY_2019_3_OR_NEWER + public string uid + { + get => viewDataKey; + set => viewDataKey = value; + } +#else + public string uid { get => persistenceKey; set => persistenceKey = value; } +#endif + + // Called when creating from Asset, calls the CreateNode method below + public static UdonNode CreateNode(UdonNodeData nodeData, UdonGraph view) + { + UdonNodeDefinition definition = UdonEditorManager.Instance.GetNodeDefinition(nodeData.fullName); + if (definition == null) + { + Debug.LogError($"Cannot create node {nodeData.fullName} because there is no matching Node Definition"); + return null; + } + + return CreateNode(definition, view, nodeData); + } + + // Always called when creating UdonNode + public static UdonNode CreateNode(UdonNodeDefinition definition, UdonGraph view, UdonNodeData nodeData = null) + { + Type type = typeof(UdonNode); + // overwrite type with target type if it exists + if (DefinitionToTypeLookup.TryGetValue(definition.fullName, out Type childType)) + { + type = childType; + } + UdonNode node = Activator.CreateInstance(type, definition, view, nodeData) as UdonNode; + node?.Initialize(); + return node; + } + + private bool skipSubtitle = false; + + private Label subtitle; + // Constructor is protected to force all paths through Static factory method except for child classes + public UdonNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) + { + _graphView = view; + definition = nodeDefinition; + Undo.RecordObject(view.graphProgramAsset, "Add UdonNode"); + var registry = UdonGraphExtensions.GetRegistryForDefinition(nodeDefinition); + if(registry != null) + { + this._registry = registry; + } + else + { + Debug.LogWarning($"Couldn't find registry for {nodeDefinition.fullName}"); + } + + VisualElement titleContainer = new VisualElement() + { + name = "title-container", + }; + this.Q("title").Insert(0, titleContainer); + + titleContainer.Add(this.Q("title-label")); + + subtitle = new Label("") + { + name = "subtitle", + }; + skipSubtitle = ( + _specialFlows.Contains(definition.fullName) + || definition.fullName.EndsWith("et_Variable") + || definition.fullName.StartsWithCached("Const_") + ); + + if (!skipSubtitle) + { + titleContainer.Insert(0, subtitle); + } + + name = definition.fullName; + elementTypeColor = Random.ColorHSV(0.5f, 0.6f, 0.1f, 0.2f, 0.8f, 0.9f); + + // Null is a type here, so handle it special + if (nodeDefinition.type == null) + { + AddToClassList("null"); + } + else + { + AddToClassList(definition.type.Namespace); + AddToClassList(definition.type.Name); + } + + if (nodeDefinition.fullName.Contains('_')) + { + AddToClassList(definition.fullName.Substring(0, nodeDefinition.fullName.IndexOf('_'))); + } + + // Create or validate nodeData + if (nodeData == null) + { + data = _graphView.graphData.AddNode(definition.fullName); + PopulateDefaultValues(); + ValidateNodeData(); + } + else + { + data = nodeData; + ValidateNodeData(); + SetPosition(new Rect(data.position.x, data.position.y, 0, 0)); + } + + uid = data.uid; + + // Fill in all fields, etc and add to the graph view + if (UdonGraphExtensions.ShouldShowDocumentationLink(definition)) + { + DrawHelpButton(); + } + + // Show overloads for nodes EXCEPT type, those have too many entries and break Unity UI + if (!nodeDefinition.fullName.StartsWith("Type_")) + { + RefreshOverloadPopup(); + } + + AddToClassList("UdonNode"); + + LayoutPorts(); + } + + public virtual void Initialize() + { + RefreshTitle(); + _graphView.MarkSceneDirty(); + } + + private string GetTargetVariableUid() + { + string result = ""; + if (IsVariableNode && this.data.nodeValues.Length > 0) + { + string[] parts = data.nodeValues[0].stringValue.Split('|'); + if (parts.Length > 1) + { + result = parts[1]; + } + } + return result; + } + + public void RefreshTitle() + { + if (IsVariableNode) + { + string uid = GetTargetVariableUid(); + if (!string.IsNullOrWhiteSpace(uid)) + { + string variableName = _graphView.GetVariableName(uid); + if (!string.IsNullOrWhiteSpace(variableName)) + { + switch (_variableNodeType) + { + case VariableNodeType.Set: + title = $"Set {variableName}"; + break; + case VariableNodeType.Change: + title = $"{variableName} Change"; + break; + case VariableNodeType.Get: + default: + title = variableName; + break; + } + return; + } + } + } + // Set Title + var displayTitle = UdonGraphExtensions.PrettyString(definition.name).FriendlyNameify(); + if (displayTitle == "Const_VRCUdonCommonInterfacesIUdonEventReceiver") + { + displayTitle = "UdonBehaviour"; + } + else if(displayTitle == "==" || displayTitle == "!=" || displayTitle == "+") + { + displayTitle = $"{definition.type.Name} {displayTitle}"; + } + + if (displayTitle.StartsWith("Op ")) + displayTitle = displayTitle.Replace("Op ", ""); + + title = displayTitle; + + AddToClassList(title.Replace(" ", "").ToLowerFirstChar()); + + if (definition == null) + { + Debug.LogWarning($"Definition for {this.name} is null"); + return; + } + + string className = definition.name.Split(' ').FirstOrDefault().Split('_').FirstOrDefault(); + AddToClassList(className); + + if (!skipSubtitle) + { + if (definition.fullName.StartsWith("Event_")) + { + subtitle.text = "Event"; + } + // make Constructor nodes readable + else if (definition.name == "ctor") + { + subtitle.text = definition.type.Name; + title = "Constructor"; + } + else + { + subtitle.text = className; + // temp title shenanigans + int firstSplit = definition.fullName.IndexOf("__") + 2; + if (firstSplit > 1) + { + int lastSplit = definition.fullName.IndexOf("__", firstSplit); + int stringLength = (lastSplit > -1) + ? lastSplit - firstSplit + : definition.fullName.Length - firstSplit; + string line2 = definition.fullName.Substring(firstSplit, stringLength).Replace("_", " ") + .UppercaseFirst(); + if (line2.StartsWith("Op ")) + { + line2 = line2.Replace("Op ", ""); + subtitle.text = definition.type.Name; + } + + title = line2; + } + else + { + //TODO: handle class names not found + //Debug.Log($"Couldn't find classname for {nodeDefinition.fullName}"); + } + } + } + } + + private void DrawHelpButton() + { + Button helpButton = new Button(ShowNodeDocs) + { + name = "help-button", + }; + helpButton.Add(new TextElement() + { + name = "icon", + text = "?" + }); + titleButtonContainer.Add(helpButton); + } + + private void ShowNodeDocs() + { + string url = UdonGraphExtensions.GetDocumentationLink(definition); + if (!string.IsNullOrEmpty(url)) + { + Help.BrowseURL(url); + } + } + + public override void SetPosition(Rect newPos) + { + newPos.position = GraphElementExtension.GetSnappedPosition(newPos.position); + base.SetPosition(newPos); + data.position = newPos.position; + } + + public override void UpdatePresenterPosition() + { + base.UpdatePresenterPosition(); + if (group != null) + { + group.SaveNewData(); + } + } + + public void RefreshOverloadPopup() + { + // Get overloads, draw them if we have more than one signature for this method + overloadDefinitions = CacheOverloads(); + if (overloadDefinitions != null && overloadDefinitions.Count > 1) + { + // Get index of currently selected (could cache this on node instead) + // TODO: switch to just reading this from Popup, which probably stores it + int currentIndex = 0; + for (int i = 0; i < overloadDefinitions.Count; i++) + { + if (overloadDefinitions.ElementAt(i).fullName != name) + { + continue; + } + + currentIndex = i; + break; + } + + // Build dropdown list + List options = new List(); + for (int i = 0; i < overloadDefinitions.Count; i++) + { + UdonNodeDefinition nodeDefinition = overloadDefinitions.ElementAt(i); + if (!_optionNameCache.TryGetValue(nodeDefinition, out string optionName)) + { + optionName = nodeDefinition.fullName; + // don't add overload types that take pointers, not supported + string[] splitOptionName = optionName.Split(new[] { "__" }, StringSplitOptions.None); + if (splitOptionName.Length >= 3) + { + optionName = $"({splitOptionName[2].Replace("_", ", ")})"; + } + + optionName = optionName.FriendlyNameify(); + _optionNameCache.Add(nodeDefinition, optionName); + } + + if (!_cleanerOptionNameCache.TryGetValue(nodeDefinition, out string cleanerOptionName)) + { + cleanerOptionName = + optionName.Replace("UnityEngine", "").Replace("System", "").Replace("Variable_", ""); + _cleanerOptionNameCache.Add(nodeDefinition, cleanerOptionName); + } + + options.Add(cleanerOptionName); + // optionName is what was used as the tooltip. Do we need the tooltip? + } + + // Clear out old one + if (inputContainer.Contains(_popup)) + { + inputContainer.Remove(_popup); + } + + _popup = new EditorUI.PopupField(options, currentIndex); +#if UNITY_2019_3_OR_NEWER + _popup.RegisterValueChangedCallback( +#else + _popup.OnValueChanged( +#endif + (e) => + { + // TODO - store data in the dropdown and use formatListItemCallback? + SetNewFullName(overloadDefinitions.ElementAt(_popup.index).fullName); + }); + inputContainer.Add(_popup); + } + } + + private void SetNewFullName(string newFullName) + { + data.fullName = newFullName; + definition = UdonEditorManager.Instance.GetNodeDefinition(data.fullName); + data.Resize(definition.Inputs.Count); + // Todo: see if we can get rid of this reload. Tried ValidateNodeData,LayoutPorts,RestoreConnections but noodles were left hanging + this.Reload(); + } + + private List CacheOverloads() + { + string baseIdentifier = name; + string[] splitBaseIdentifier = baseIdentifier.Split(new[] { "__" }, StringSplitOptions.None); + if (splitBaseIdentifier.Length >= 2) + { + baseIdentifier = $"{splitBaseIdentifier[0]}__{splitBaseIdentifier[1]}__"; + } + + if (baseIdentifier.StartsWithCached("Const_")) + { + return null; + } + + if (baseIdentifier.StartsWithCached("Type_")) + { + baseIdentifier = "Type_"; + } + + if (baseIdentifier.StartsWithCached("Variable_")) + { + baseIdentifier = "Variable_"; + } + + // This used to be cached on graph instead of calculated per-node + // TODO: cache this somewhere, maybe UdonEditorManager? Is that worth it for performance? + IEnumerable matchingNodeDefinitions = + UdonEditorManager.Instance.GetNodeDefinitions(baseIdentifier); + + var result = new List(); + foreach (var definition in matchingNodeDefinitions) + { + // don't add definitions with pointer parameters, not supported in Udon + if (!definition.fullName.Contains('*')) + { + result.Add(definition); + } + } + + return result; + } + + internal void RestoreConnections() + { + RestoreInputs(); + RestoreFlows(); + } + + private void RestoreFlows() + { + for (int i = 0; i < data.flowUIDs.Length; i++) + { + // skip if flow uid is empty + string nodeUID = data.flowUIDs[i]; + if (string.IsNullOrEmpty(nodeUID)) + { + continue; + } + + // Find connected node via Graph + UdonNode connectedNode = _graphView.GetNodeByGuid(nodeUID) as UdonNode; + if (connectedNode == null) + { + Debug.Log($"Couldn't find node with GUID {nodeUID}, clearing data"); + data.flowUIDs[i] = ""; + continue; + } + + // Trying to move a Block's flow that was left at the end to the beginning + if (portsFlowOut != null && i >= portsFlowOut.Count) + { + Debug.LogWarning( + $"Trying to restore flow to {connectedNode.name} from a non-existent port, skipping"); + + for (int j = 0; j < data.flowUIDs.Length; j++) + { + bool didRestoreFlow = false; + if (string.IsNullOrEmpty(data.flowUIDs[j])) + { + data.flowUIDs[j] = data.flowUIDs[i]; + data.flowUIDs[i] = ""; + didRestoreFlow = true; + } + + if (didRestoreFlow) + { + RestoreFlows(); + } + } + + continue; + } + + UdonPort sourcePort = null; + // Edge case, but its possible that this is null in broken graphs + // Skip if we can't find the source port + if (portsFlowOut != null) + { + sourcePort = portsFlowOut.Count > 1 ? portsFlowOut[i] : portsFlowOut.FirstOrDefault(); + if (sourcePort == null) + { + Debug.LogError($"Failed to find output flow port for node {uid}"); + // clear the flow uid, user will have to reconnect by hand + data.flowUIDs[i] = ""; + continue; + } + } + else + { + Debug.LogError($"Failed to find output flow port for node {uid}"); + // clear the flow uid, user will have to reconnect by hand + data.flowUIDs[i] = ""; + continue; + } + + + UdonPort destPort = null; + // Edge case, but its possible that this is null in broken graphs + if(connectedNode.portsFlowIn != null) + { + destPort = connectedNode.portsFlowIn.FirstOrDefault(); + if (destPort == null) + { + Debug.LogError($"Failed to find input flow port node node {nodeUID}"); + // clear the flow uid, user will have to reconnect by hand + data.flowUIDs[i] = ""; + continue; + } + } + else + { + Debug.LogError($"Failed to find input flow port node node {nodeUID}"); + // clear the flow uid, user will have to reconnect by hand + data.flowUIDs[i] = ""; + continue; + } + + // Passed the tests! ready to connect + var edge = sourcePort.ConnectTo(destPort); + edge.AddToClassList("flow"); + _graphView.AddElement(edge); + } + + } + + private void RestoreInputs() + { + for (int i = 0; i < definition.Inputs.Count; i++) + { + // Skip to next input if we don't have a node to check at this index + if (data.nodeUIDs.Length <= i) + { + continue; + } + + // Skip to next input if we have a bad node reference + if (string.IsNullOrEmpty(data.nodeUIDs[i])) + { + continue; + } + + // get otherIndex. not 100% sure what this refers to yet, maybe a port index? + string[] splitUID = data.nodeUIDs[i].Split('|'); + string nodeUID = splitUID[0]; + int otherIndex = 0; + if (splitUID.Length > 1) + { + otherIndex = int.Parse(splitUID[1]); + } + + // Skip if we don't have a good uid for the other node + if (string.IsNullOrEmpty(nodeUID)) + { + continue; + } + + // Find connected node via Graph + UdonNode connectedNode = _graphView.GetNodeByGuid(nodeUID) as UdonNode; + if (connectedNode == null) + { + Debug.Log($"Couldn't find node with GUID {nodeUID}"); + data.nodeUIDs[i] = ""; + continue; + } + + // No matching port for this data, skip + if (portsIn == null) continue; + if (!portsIn.TryGetValue(i, out UdonPort destPort)) + { + Debug.LogError($"Failed to find input data slot (index {i}) for node {uid} {data.fullName}"); + continue; + } + + // Copied from Legacy, not sure what conditions would cause this + if (otherIndex < 0 || connectedNode?.portsOut.Keys.Count <= otherIndex) + { + otherIndex = 0; + } + + // skip if we can't find the sourcePort - comment better once you understand what this is exactly + if (connectedNode == null || !connectedNode.portsOut.TryGetValue(otherIndex, out UdonPort sourcePort)) + { + Debug.LogError($"Failed to find output data slot for node {nodeUID}"); + continue; + } + + // Passed the tests! ready to connect + var edge = sourcePort.ConnectTo(destPort); + _graphView.AddElement(edge); + } + } + + // Legacy, haven't gone through yet + void ValidateNodeData() + { + // set data to this graph + data.SetGraph(_graphView.graphData); + + for (int i = 0; i < data.nodeValues.Length; i++) + { + if (definition.Inputs.Count <= i) + { + continue; + } + + Type expectedType = definition.Inputs[i].type; + + // Skip over if the value is null and that's ok + if (data.nodeValues[i] == null) + { + if (expectedType == null || Nullable.GetUnderlyingType(expectedType) != null) + { + continue; + } + else + { + data.nodeValues[i] = SerializableObjectContainer.Serialize(default, expectedType); + continue; + } + } + + object value = data.nodeValues[i].Deserialize(); + if (value == null) + { + if (expectedType == null || Nullable.GetUnderlyingType(expectedType) != null) + { + // type is nullable, leave it alone + continue; + } + else + { + // not a nullable type - set a default + data.nodeValues[i] = SerializableObjectContainer.Serialize(default, expectedType); + } + } + + if (!expectedType.IsInstanceOfType(value)) + { + data.nodeValues[i] = SerializableObjectContainer.Serialize(null, expectedType); + } + } + } + + void PopulateDefaultValues() + { + // No default values so I'm just...making them? + int count = definition.Inputs.Count; + + data.nodeValues = new SerializableObjectContainer[count]; + data.nodeUIDs = new string[count]; + for (int i = 0; i < count; i++) + { + object value = definition.defaultValues.Count > i ? definition.defaultValues[i] : default; + data.nodeValues[i] = SerializableObjectContainer.Serialize(value, definition.Inputs[i].type); + } + } + + private enum VariableNodeType + { + Get, + Set, + None, + Change, + }; + + private VariableNodeType _variableNodeType = VariableNodeType.None; + + + public virtual void LayoutPorts() + { + ClearPorts(); + SetupFlowPorts(); + + // Don't setup in ports for Get_Variable node types, instead add variable popup + if (name.CompareTo("Get_Variable") == 0) + { + _variableNodeType = VariableNodeType.Get; + RefreshVariablePopup(); + } + else if (name.CompareTo("Event_OnVariableChange") == 0) + { + _variableNodeType = VariableNodeType.Change; + } + else + { + // Add Variable popup and in-ports for Set_Variable + if (name.CompareTo("Set_Variable") == 0) + { + _variableNodeType = VariableNodeType.Set; + RefreshVariablePopup(); + } + + SetupInPorts(); + } + + SetupOutPorts(); + + RefreshExpandedState(); + RefreshPorts(); + } + + public void ClearPorts() + { + portsFlowIn?.ForEach(port => port.RemoveFromHierarchy()); + portsFlowOut?.ForEach(port => port.RemoveFromHierarchy()); + portsIn?.Values.ForEach(port => port.RemoveFromHierarchy()); + portsOut?.Values.ForEach(port => port.RemoveFromHierarchy()); + } + + private EditorUI.PopupField _variablePopupField; + // TODO: Test this again after we have the new graph serializing the addition of nodes + public void RefreshVariablePopup() + { + if (_variableNodeType == VariableNodeType.None) + { + Debug.LogError($"Not Creating Variable Pop-Up for Non Variable Node {data.fullName}"); + } + + // Legacy method of determining currently selected index + // TODO: upgrade this logic path from the legacy method of determining Variable indices + // Get Variable nodes only have one value, get it and deserialize + + var value = data.nodeValues[0].Deserialize(); + + var options = _graphView.GetVariableNames.Where(t => !t.StartsWith("__")).ToList(); + + // Get value of selected node in rather roundabout way + int originalIndex = _graphView.GetVariableNodes + .IndexOf(_graphView.GetVariableNodes.FirstOrDefault(v => v.uid == (string)value)); + + // Allow OnVariableChange events to start with just any existing index + if (_variableNodeType == VariableNodeType.Change && originalIndex == -1) originalIndex = 0; + + int currentIndex = _graphView.GetVariableNames.FindIndex(s => s == _graphView.GetVariableNames[originalIndex]); + + if (currentIndex < 0) + { + Debug.LogWarning($"Node {name} didn't have a variable assigned, removing"); + _graphView.RemoveNodeAndData(data); + return; + } + + // Create popup, set current value and set function to update data when it's changed. + if (_variablePopupField == null) + { + // First time creating, just add it + _variablePopupField = new EditorUI.PopupField(options, currentIndex); + inputContainer.Add(_variablePopupField); + } + else + { + // Remaking it - remove the old one, at the new one at its previous location + int index = inputContainer.IndexOf(_variablePopupField); + _variablePopupField.RemoveFromHierarchy(); + _variablePopupField = new EditorUI.PopupField(options, currentIndex); + inputContainer.Insert(index, _variablePopupField); + } +#if UNITY_2019_3_OR_NEWER + _variablePopupField.RegisterValueChangedCallback( +#else + _variablePopupField.OnValueChanged( +#endif + (e) => + { + // Ensure we've selected an existing variable + if (_variablePopupField.index < options.Count) + { + int trueIndex = _graphView.GetVariableNames.FindIndex(s => s == _variablePopupField.text); + + // not currently using event value, which is variable name. Instead using legacy method of comparing index to graph variable nodes array index + string newUid = _graphView.GetVariableNodes[trueIndex].uid; + // Get Variable nodes only have one entry, so index is 0 below + SetNewValue(newUid, 0); + + this.Reload(); // Didn't want to do this, but can't get flows to restore otherwise Ideally, we call RefreshTitle(), LayoutPorts(), RestoreConnections(), RestoreFlows() + } + }); + + string startingUid = _graphView.GetVariableNodes[originalIndex].uid; + SetNewValue(startingUid, 0); + } + + public void SetNewValue(object newValue, int index, Type inType = null) + { + data.nodeValues[index] = SerializableObjectContainer.Serialize(newValue, inType); + } + + private void SetupOutPorts() + { + portsOut = new Dictionary(); + for (int i = 0; i < definition.Outputs.Count; i++) + { + var item = definition.Outputs[i]; + + // Convert object type to variable type for Get_Variable nodes, or run them through the SlotTypeConverter for all other nodes + Type type = (_variableNodeType == VariableNodeType.Get || _variableNodeType == VariableNodeType.Change) + ? GetTypeForDefinition(definition) + : UdonGraphExtensions.SlotTypeConverter(item.type, definition.fullName); + + string label = UdonGraphExtensions.FriendlyTypeName(type).FriendlyNameify(); + if (label == "IUdonEventReceiver") + { + label = "UdonBehaviour"; + } + + if (item.name != null) label = $"{label} {item.name}"; + UdonPort port = (UdonPort) UdonPort.Create(label, Direction.Output, this, type, data, i); + outputContainer.Add(port); + portsOut[i] = port; + } + } + + private void SetupInPorts() + { + portsIn = new Dictionary(); + + // Expand node data to hold values for all inputs + data.Resize(definition.Inputs.Count); + + int startIndex = 0; + // Skip first input for Set_Variable since that's the eventName which is set via dropdown + if (name.CompareTo("Set_Variable") == 0) + { + startIndex = 1; + } + // Skip first input for Set_ReturnValue since that's the special variable + if (name.CompareTo("Set_ReturnValue") == 0) + { + startIndex = 1; + } + + // Skip inputs for Null and This nodes + if (name.Contains("Const_Null") || name.Contains("Const_This")) + { + return; + } + + for (int index = startIndex; index < definition.Inputs.Count; index++) + { + UdonNodeParameter input = definition.Inputs[index]; + string label = ""; + // TODO: Ask Cubed what this does? Or figure it out. + if (definition.Inputs.Count > index && index >= 0) + { + label = definition.Inputs[index].name; + } + + if (label == "IUdonEventReceiver") + { + label = "UdonBehaviour"; + } + + label = label.FriendlyNameify(); + string typeName = UdonGraphExtensions.FriendlyTypeName(input.type); + + // skip over types with pointers. Should remove these from included overloads in the first place! + if (typeName.Contains('*')) + { + continue; + } + + // Convert object type to variable type for Set_Variable nodes, or run them through the SlotTypeConverter for all other nodes + Type type = (_variableNodeType == VariableNodeType.Set && index == 1) + ? type = GetTypeForDefinition(definition) + : UdonGraphExtensions.SlotTypeConverter(input.type, definition.fullName); + + if (_variableNodeType == VariableNodeType.Set && index == 2) + { + AddToClassList("send-change"); + } + + // not 100% sure if I should use label or typeName here + UdonPort p = UdonPort.Create(label, Direction.Input, this, type, data, index) as UdonPort; + inputContainer.Add(p); + portsIn.Add(index, p); + } + } + + private Type GetTypeForDefinition(UdonNodeDefinition udonNodeDefinition) + { + string targetUid = data.nodeValues[0].Deserialize().ToString(); + UdonNodeData varData = _graphView.GetVariableNodes.Where(n => n.uid == targetUid).FirstOrDefault(); + if (varData != null) + { + var targetDefinition = UdonEditorManager.Instance.GetNodeDefinition(varData.fullName); + if (targetDefinition != null) + { + return UdonGraphExtensions.SlotTypeConverter(targetDefinition.type, udonNodeDefinition.fullName); + } + } + + // if we fail, return generic object type + return typeof(object); + } + + private void SetupFlowPorts() + { + if (definition.flow) + { + portsFlowIn = new List(); + portsFlowOut = new List(); + + string label = ""; + + int inFlowIndex = -1; + int outFlowIndex = -1; + // don't add input flow for events, they're called from above + if (!definition.fullName.StartsWith("Event_")) + { + label = definition.inputFlowNames.Count > 0 ? definition.inputFlowNames[0] : ""; + AddFlowPort(Direction.Input, label, ++inFlowIndex); + } + + // add output flow + label = definition.outputFlowNames.Count > 0 ? definition.outputFlowNames[0] : ""; + AddFlowPort(Direction.Output, label, ++outFlowIndex); + if (_specialFlows.Contains(definition.fullName)) + { + label = definition.outputFlowNames.Count > 1 ? definition.outputFlowNames[1] : ""; + AddFlowPort(Direction.Output, label, ++outFlowIndex); + } + + // Add the number of output flows we need for a Block + if (definition.fullName == "Block") + { + data.flowUIDs = data.flowUIDs.Where(f => !string.IsNullOrEmpty(f)).ToArray(); + int connectedFlows = data.flowUIDs.Length; + if (connectedFlows > 1) + { + for (int i = 0; i < connectedFlows - 1; i++) + { + AddFlowPort(Direction.Output, "", ++outFlowIndex); + } + } + } + } + } + + private void AddFlowPort(Direction d, string label, int index) + { + UdonPort p = (UdonPort) UdonPort.Create(label, d, this, null, data, index); + p.AddToClassList("flow"); + if(d == Direction.Input) + { + inputContainer.Add(p); + portsFlowIn.Add(p); + } + else + { + outputContainer.Add(p); + portsFlowOut.Add(p); + } + } + + private bool HasRecursiveFlow(Port fromSlot, Port toSlot) + { + // No need to check connections to value slots + if (toSlot.portType != null) return false; + + // Check out ports of node being connected TO + foreach (var port in (toSlot.node as UdonNode).portsFlowOut) + { + // if any of its ports connect to fromSlot, it's recursive. using foreach for convenience, should be just one edge + foreach (var edge in port.connections) + { + // if this connection goes to the node that started this all, then it's recursion + if(edge.input.node == fromSlot.node) + { + return true; + } + + // Need to run this recursively to check all ports + if(HasRecursiveFlow(fromSlot, edge.input)) + { + return true; + } + } + } + + return false; + } + + #region IEdgeConnectorListener + + public void OnDrop(EditorGV.GraphView graphView, Edge edge) + { + if (edge.output != null && edge.input != null && !HasRecursiveFlow(edge.output, edge.input)) + { + edge.output.Connect(edge); + edge.input.Connect(edge); + graphView.AddElement(edge); + + // Reload block nodes after new connections + if(definition.fullName == "Block") + { + RestoreFlows(); + } + } + } + + public void OnDropOutsidePort(Edge edge, Vector2 position) + { + if (!Settings.SearchOnNoodleDrop) return; + + if (edge.output != null && edge.output.portType != null) + { + _graphView.OpenPortSearch(edge.output.portType, position, edge.output as UdonPort, Direction.Input); + } + else if (edge.input != null && edge.input.portType != null) + { + _graphView.OpenPortSearch(edge.input.portType, position, edge.input as UdonPort, Direction.Output); + } + } + + #endregion + } +} diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNode.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNode.cs.meta new file mode 100644 index 00000000..426e8041 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: dcd657bc1dcf357448d27bcfa8c5dc36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes.meta new file mode 100644 index 00000000..99b3dc3d --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50be104b42303f24fa6166d0c5b542f1 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/GetOrSetProgramVariableNode.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/GetOrSetProgramVariableNode.cs new file mode 100644 index 00000000..1521f75c --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/GetOrSetProgramVariableNode.cs @@ -0,0 +1,30 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +using EngineUI = UnityEngine.UIElements; +using EditorUI = UnityEditor.UIElements; +#else +using EditorGV = UnityEditor.Experimental.UIElements.GraphView; +using EngineUI = UnityEngine.Experimental.UIElements; +using EditorUI = UnityEditor.Experimental.UIElements; +#endif +using VRC.Udon.Graph; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView.UdonNodes +{ + public class GetOrSetProgramVariableNode : UdonNode + { + private EditorUI.PopupField _programVariablePopup; + + public GetOrSetProgramVariableNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : + base(nodeDefinition, view, nodeData) + { + } + + public override void Initialize() + { + base.Initialize(); + _programVariablePopup = + this.GetProgramPopup(UdonNodeExtensions.ProgramPopupType.Variables, _programVariablePopup); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/GetOrSetProgramVariableNode.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/GetOrSetProgramVariableNode.cs.meta new file mode 100644 index 00000000..243a80e5 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/GetOrSetProgramVariableNode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: cbfa6b1c2cf44feca09853837fc740bb +timeCreated: 1623890922 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SendCustomEventNode.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SendCustomEventNode.cs new file mode 100644 index 00000000..1d8b75ef --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SendCustomEventNode.cs @@ -0,0 +1,28 @@ +#if UNITY_2019_3_OR_NEWER +using EditorGV = UnityEditor.Experimental.GraphView; +using EngineUI = UnityEngine.UIElements; +using EditorUI = UnityEditor.UIElements; +#else +using EditorGV = UnityEditor.Experimental.UIElements.GraphView; +using EngineUI = UnityEngine.Experimental.UIElements; +using EditorUI = UnityEditor.Experimental.UIElements; +#endif +using VRC.Udon.Graph; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView.UdonNodes +{ + public class SendCustomEventNode : UdonNode + { + private EditorUI.PopupField _eventNamePopup; + + public SendCustomEventNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData) + { + } + + public override void Initialize() + { + base.Initialize(); + _eventNamePopup = this.GetProgramPopup(UdonNodeExtensions.ProgramPopupType.Events, _eventNamePopup); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SendCustomEventNode.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SendCustomEventNode.cs.meta new file mode 100644 index 00000000..a71b401c --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SendCustomEventNode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 8164fc2c5c5b43428503cf064e8b53f0 +timeCreated: 1624411228 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetReturnValueNode.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetReturnValueNode.cs new file mode 100644 index 00000000..30691476 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetReturnValueNode.cs @@ -0,0 +1,42 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +using EditorGV = UnityEditor.Experimental.GraphView; +using EngineUI = UnityEngine.UIElements; +using EditorUI = UnityEditor.UIElements; +using UnityEngine.UIElements; +#else +using EditorGV = UnityEditor.Experimental.UIElements.GraphView; +using EngineUI = UnityEngine.Experimental.UIElements; +using EditorUI = UnityEditor.Experimental.UIElements; +#endif +using System.Linq; +using UnityEngine; +using VRC.Udon.Graph; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView.UdonNodes +{ + public class SetReturnValueNode : UdonNode + { + public SetReturnValueNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData) + { + } + + public override void Initialize() + { + base.Initialize(); + + string returnVariable = UdonBehaviour.ReturnVariableName; + string uuid = null; + + if (!_graphView.GetVariableNames.Contains(returnVariable)) + uuid = _graphView.AddNewVariable("Variable_SystemObject", returnVariable, false); + else + uuid = _graphView.GetVariableNodes.FirstOrDefault(n => (string)n.nodeValues[1].Deserialize() == returnVariable)?.uid; + + if (!string.IsNullOrWhiteSpace(uuid)) + SetNewValue(uuid, 0); + else + Debug.LogError("Could not find return value name!"); + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetReturnValueNode.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetReturnValueNode.cs.meta new file mode 100644 index 00000000..6c3ac32b --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetReturnValueNode.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6e65118bfe2d43f1ad2412dba47c21ee +timeCreated: 1623892831 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetVariableNode.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetVariableNode.cs new file mode 100644 index 00000000..97176a9e --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetVariableNode.cs @@ -0,0 +1,25 @@ +using UnityEngine; +using UnityEngine.UIElements; +using VRC.Udon.Graph; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView.UdonNodes +{ + public class SetVariableNode : UdonNode + { + public SetVariableNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData) + { + } + + public override void Initialize() + { + base.Initialize(); + + UdonPort sendChangePort = portsIn[2]; + var toggle = sendChangePort.Q(); + if (toggle != null) + { + sendChangePort.Insert(0, toggle); + } + } + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetVariableNode.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetVariableNode.cs.meta new file mode 100644 index 00000000..21ef0abe --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/SetVariableNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: fd9209fd8a363ee42a49a2afaeb35805 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/UdonNodeExtensions.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/UdonNodeExtensions.cs new file mode 100644 index 00000000..c650e567 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/UdonNodeExtensions.cs @@ -0,0 +1,164 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +using EditorGV = UnityEditor.Experimental.GraphView; +using EngineUI = UnityEngine.UIElements; +using EditorUI = UnityEditor.UIElements; +using UnityEngine.UIElements; +#else +using UnityEditor.Experimental.UIElements.GraphView; +using EditorGV = UnityEditor.Experimental.UIElements.GraphView; +using EngineUI = UnityEngine.Experimental.UIElements; +using EditorUI = UnityEditor.Experimental.UIElements; +using UnityEngine.Experimental.UIElements; +#endif +using System.Collections.Generic; +using System.Linq; +using UnityEngine; +using VRC.Udon.Common; +using VRC.Udon.Compiler.Compilers; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView.UdonNodes +{ + public static class UdonNodeExtensions + { + + #region Methods for creating popup selectors from Program variables / event + public static readonly HashSet InternalEventNames = new HashSet() + { + "_start", "_update", "_lateUpdate", "_fixedUpdate", "onAnimatorIk", "_onAnimatorMove", "_onBecameInvisible", "_onBecameVisible", + "_onPlayerCollisionEnter", "_onCollisionEnter", "_onCollisionEnter2D", "_onPlayerCollisionExit", "_onCollisionExit", "_onCollisionExit2D", "_onPlayerCollisionStay", "_onCollisionStay", "_onCollisionStay2D", + "_onPlayerTriggerEnter", "_onTriggerEnter", "_onTriggerEnter2D", "_onPlayerTriggerExit", "_onTriggerExit", "_onTriggerExit2D", "_onPlayerTriggerStay", "_onTriggerStay", "_onTriggerStay2D", + "_onDestroy", "_onDisable", "_onDrawGizmos", "_onDrawGizmosSelected", "_onEnable", "_onJointBreak", "_onJointBreak2D", "_onMouseDown", "_onMouseDrag", "_onMouseEnter", "_onMouseExit", "_onMouseOver", "_onMouseUp", "_onMouseUpAsButton", + "_onPlayerParticleCollision", "_onParticleCollision", "_onParticleTrigger", "_onPostRender", "_onPreCull", "_onPreRender", "_onRenderImage", "_onRenderObject", "_onTransformChildrenChanged", "_onTransformParentChanged", "_onValidate", "_onWillRenderObject", + "_interact", "_onDrop", "_onPickup", "_onPickupUseDown", "_onPickupUseUp", "_onPreSerialization", "_onPostSerialization", "_onDeserialization", "_onVideoEnd", "_onVideoPause", "_onVideoPlay", "_onVideoStart", "_midiNoteOn", "_midiNoteOff", "_midiControlChange", + "_onOwnershipRequest", "_onNetworkReady", "_onOwnershipTransferred", "_onPlayerJoined", "_onPlayerLeft", "_onSpawn", "_onStationEntered", "_onStationExited", + }; + + public enum ProgramPopupType + { + Variables, Events + } + + private static List GetCustomEventsFromAsset(AbstractSerializedUdonProgramAsset asset) + { + // don't return internal event names or VariableChange events + return asset.RetrieveProgram().EntryPoints.GetExportedSymbols().Where(e => + !InternalEventNames.Contains(e) && !e.StartsWithCached(VariableChangedEvent.EVENT_PREFIX)).ToList(); + } + + public static EditorUI.PopupField GetProgramPopup(this UdonNode node, ProgramPopupType popupType, EditorUI.PopupField _eventNamePopup) + { + string PLACEHOLDER = "----"; + string MISSING = "MISSING! Was"; + + List _options = new List(){PLACEHOLDER}; + var data = node.data; + + bool unavailable = true; + if(data.nodeUIDs.Length < 1 || string.IsNullOrEmpty(data.nodeUIDs[0])) + { + switch (popupType) + { + case ProgramPopupType.Events: + _options = GetCustomEventsFromAsset(node.Graph.graphProgramAsset.SerializedProgramAsset); + break; + case ProgramPopupType.Variables: + node.Graph.RefreshVariables(false); + _options = new List(node.Graph.GetVariableNames).Where(x=>!x.StartsWithCached(VariableChangedEvent.OLD_VALUE_PREFIX)).ToList(); + break; + } + unavailable = _options.Count == 0; + _options.Insert(0, PLACEHOLDER); + } + else if(data.InputNodeAtIndex(0)?.fullName == "Get_Variable") + { + // So much work to get the underlying node referenced by a variable. Would be nice to have a method for this. + var parts = data.nodeUIDs[0].Split('|'); + if (parts.Length < 1) return null; + + string targetId = parts[0]; + + var variableGetterNode = node.Graph.graphData.FindNode(targetId); + if (variableGetterNode == null || variableGetterNode.nodeValues.Length < 1) return null; + + string variableId = variableGetterNode.nodeValues[0].Deserialize() as string; + if (string.IsNullOrWhiteSpace(variableId)) return null; + + string variableName = node.Graph.GetVariableName(variableId); + if (string.IsNullOrWhiteSpace(variableName)) return null; + + if (node.Graph.udonBehaviour != null && node.Graph.udonBehaviour.publicVariables.TryGetVariableValue(variableName, out UdonBehaviour ub)) + { + if (ub != null) + { + switch (popupType) + { + case ProgramPopupType.Events: + _options = GetCustomEventsFromAsset(ub.programSource.SerializedProgramAsset); + break; + case ProgramPopupType.Variables: + _options = ub.programSource?.SerializedProgramAsset?.RetrieveProgram()?.SymbolTable + .GetSymbols().Where(s => !s.StartsWithCached(UdonGraphCompiler.INTERNAL_VARIABLE_PREFIX) && !s.StartsWithCached(VariableChangedEvent.OLD_VALUE_PREFIX)).ToList(); + break; + } + _options.Insert(0, PLACEHOLDER); + unavailable = false; + } + } + } + + + int currentIndex = 0; + int targetNodeValueIndex = node.data.fullName.Contains("SendCustomNetworkEvent") ? 2 : 1; + string targetVarName = data.nodeValues[targetNodeValueIndex].Deserialize() as string; + if (targetVarName != null && targetVarName.StartsWithCached(MISSING)) targetVarName = null; + + // If we have a target variable name: + if (!string.IsNullOrWhiteSpace(targetVarName)) + { + if (_options.Contains(targetVarName)) + { + currentIndex = _options.IndexOf(targetVarName); + } + else + { + _options[0] = unavailable ? targetVarName : $"{MISSING} {targetVarName}"; + } + } + + if (_eventNamePopup == null) + { + _eventNamePopup = new EditorUI.PopupField(_options, currentIndex); + _eventNamePopup.name = popupType == ProgramPopupType.Events ? "EventNamePopup" : "VariablePopup"; + var eventNamePort = node.inputContainer.Q(null, popupType == ProgramPopupType.Events ? "eventName" : "symbolName"); + eventNamePort?.Add(_eventNamePopup); + if (unavailable) + { + _eventNamePopup.SetEnabled(false); + } + } + else + { + // Remaking it - remove the old one, at the new one at its previous location + int index = node.inputContainer.IndexOf(_eventNamePopup); + _eventNamePopup.RemoveFromHierarchy(); + _eventNamePopup = new EditorUI.PopupField(_options, currentIndex); + node.inputContainer.Insert(index, _eventNamePopup); + } +#if UNITY_2019_3_OR_NEWER + _eventNamePopup.RegisterValueChangedCallback( +#else + _eventNamePopup.OnValueChanged( +#endif + (e) => + { + node.SetNewValue(e.newValue.CompareTo(PLACEHOLDER) == 0 ? "" : e.newValue.ToString(), targetNodeValueIndex); + // Todo: update text field directly and save instead of calling Reload + node.Reload(); + }); + + return _eventNamePopup; + } + #endregion + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/UdonNodeExtensions.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/UdonNodeExtensions.cs.meta new file mode 100644 index 00000000..93534521 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonNodes/UdonNodeExtensions.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 00b770580aae40ffb9f6a1d898b52269 +timeCreated: 1625678192 \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonPort.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonPort.cs new file mode 100644 index 00000000..8b808489 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonPort.cs @@ -0,0 +1,450 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEditor.Experimental.GraphView; +using UnityEngine.UIElements; +using EditorUI = UnityEditor.UIElements; +using EngineUI = UnityEngine.UIElements; +#else +using UnityEditor.Experimental.UIElements.GraphView; +using UnityEngine.Experimental.UIElements; +using EditorUI = UnityEditor.Experimental.UIElements; +using EngineUI = UnityEngine.Experimental.UIElements; +#endif +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; +using VRC.Udon.Graph; +using VRC.Udon.Serialization; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + [Serializable] + public class UdonPort : Port + { + public string FullName; + private UdonNodeData _udonNodeData; + private int _nodeValueIndex; + + private VisualElement _inputField; + private VisualElement _inputFieldTypeLabel; + + private IArrayProvider _inspector; + + protected UdonPort(Orientation portOrientation, Direction portDirection, Capacity portCapacity, Type type) : + base(portOrientation, portDirection, portCapacity, type) + { + } + + public static Port Create(string portName, Direction portDirection, IEdgeConnectorListener connectorListener, + Type type, UdonNodeData data, int index, Orientation orientation = Orientation.Horizontal) + { + + Capacity capacity = Capacity.Single; + if (portDirection == Direction.Input && type == null || portDirection == Direction.Output && type != null) + { + capacity = Capacity.Multi; + } + + UdonPort port = new UdonPort(orientation, portDirection, capacity, type) + { + m_EdgeConnector = new EdgeConnector(connectorListener), + }; + + port.portName = portName; + port._udonNodeData = data; + port._nodeValueIndex = index; + + port.SetupPort(); + return port; + } + + public int GetIndex() + { + return _nodeValueIndex; + } + + private bool _isSendChangePort = false; + + private void SetupPort() + { + _isSendChangePort = portName == "sendChange"; + if (_isSendChangePort) + { + m_EdgeConnector = null; + } + else + { + this.AddManipulator(m_EdgeConnector); + } + + tooltip = UdonGraphExtensions.FriendlyTypeName(portType); + + FullName = _udonNodeData.fullName; + + if (portType == null || direction == Direction.Output) + { + return; + } + + if (TryGetValueObject(out object result, portType)) + { + var field = UdonFieldFactory.CreateField( + portType, + result, + newValue => SetNewValue(newValue) + ); + + if (field != null) + { + SetupField(field); + } + } + + if (_udonNodeData.fullName.StartsWithCached("Const")) + { + RemoveConnectorAndLabel(); + } + else if (_udonNodeData.fullName.StartsWithCached("Set_Variable") && _nodeValueIndex == 2) + { + _isSendChangePort = true; + RemoveConnector(); + AddToClassList("send-change"); + } + + AddToClassList(portName); + + UpdateLabel(connected); + } + + // Made its own method for now as we have issues auto-converting between string and char in a TextField + // TODO: refactor SetupField so we can do just the field.value part separately to combine with this + private VisualElement SetupCharField() + { + TextField field = new TextField(); + field.AddToClassList("portField"); + if (TryGetValueObject(out object result)) + { + field.value = UdonGraphExtensions.UnescapeLikeALiteral((char) result); + } + + field.isDelayed = true; + + // Special handling for escaping char value +#if UNITY_2019_3_OR_NEWER + field.RegisterValueChangedCallback( +#else + field.OnValueChanged( +#endif + e => + { + if (e.newValue[0] == '\\' && e.newValue.Length > 1) + { + SetNewValue(UdonGraphExtensions.EscapeLikeALiteral(e.newValue.Substring(0, 2))); + } + else + { + SetNewValue(e.newValue[0]); + } + }); + _inputField = field; + + // Add label, shown when input is connected. Not shown by default + var friendlyName = UdonGraphExtensions.FriendlyTypeName(typeof(char)).FriendlyNameify(); + var label = new Label(friendlyName); + _inputFieldTypeLabel = label; + + return _inputField; + } + + private void SetupField(VisualElement field) + { + // Custom Event fields need their event names sanitized after input and their connectors removed + if (_udonNodeData.fullName.CompareTo("Event_Custom") == 0) + { + var tfield = (TextField) field; +#if UNITY_2019_3_OR_NEWER + tfield.RegisterValueChangedCallback( +#else + tfield.OnValueChanged( +#endif + (e) => + { + string newValue = e.newValue.SanitizeVariableName(); + tfield.value = newValue; + SetNewValue(newValue); + }); + RemoveConnectorAndLabel(); + } + + // Add label, shown when input is connected. Not shown by default + var friendlyName = UdonGraphExtensions.FriendlyTypeName(portType).FriendlyNameify(); + var label = new Label(friendlyName); + _inputFieldTypeLabel = label; + field.AddToClassList("portField"); + + _inputField = field; + Add(_inputField); + } + + private void RemoveConnectorAndLabel() + { + RemoveConnector(); + this.Q(null, "connectorText")?.RemoveFromHierarchy(); + } + + private void RemoveConnector() + { + this.Q("connector")?.RemoveFromHierarchy(); + } + +#pragma warning disable 0649 // variable never assigned + private Button _editArrayButton; + + private void EditArray(Type elementType) + { + // Update Values when 'Save' is clicked + if (_inspector != null) + { + // Update Values + SetNewValue(_inspector.GetValues()); + + // Remove Inspector + _inspector.RemoveFromHierarchy(); + _inspector = null; + + // Update Button Text + _editArrayButton.text = "Edit"; + return; + } + + // Otherwise set up the inspector + _editArrayButton.text = "Save"; + + // Get value object, null is ok + TryGetValueObject(out object value); + + // Create it new + Type typedArrayInspector = (typeof(UdonArrayInspector<>)).MakeGenericType(elementType); + _inspector = (Activator.CreateInstance(typedArrayInspector, value) as IArrayProvider); + + parent.Add(_inspector as VisualElement); + } + + // Update elements on connect + public override void Connect(Edge edge) + { + AddToClassList("connected"); + base.Connect(edge); + + Undo.RecordObject(((UdonNode)node).Graph.graphProgramAsset, "Connect Edge"); + + // The below logic is just for Output ports + if (edge.input.Equals(this)) return; + + // hide field, show label + var input = ((UdonPort) edge.input); + input.UpdateLabel(true); + + if (IsReloading()) + { + return; + } + + // update data + if (portType == null) + { + // We are a flow port + SetFlowUID(((UdonNode) input.node).uid); + this.Compile(); + } + else + { + // We are a value port, we need to send our info over to the OTHER node + string myNodeUid = ((UdonNode) node).uid; + input.SetDataFromNewConnection($"{myNodeUid}|{_nodeValueIndex}", input.GetIndex()); + } + + if (_isSendChangePort) + { + DisconnectAll(); + this.Reload(); + } + } + + public override void OnStopEdgeDragging() + { + base.OnStopEdgeDragging(); + + if (edgeConnector?.edgeDragHelper?.draggedPort == this) + { + if (capacity == Capacity.Single && connections.Count() > 0) + { + // This port could only have one connection. Fixed in Reserialize, need to reload to show the change + this.Reload(); + } + } + else + { + this.Reload(); + } + } + + private void SetFlowUID(string newValue) + { + if (_udonNodeData.flowUIDs.Length <= _nodeValueIndex) + { + // If we don't have space for this flow value, create a new array + // TODO: handle this elsewhere? + var newFlowArray = new string[_nodeValueIndex + 1]; + for (int i = 0; i < _udonNodeData.flowUIDs.Length; i++) + { + newFlowArray[i] = _udonNodeData.flowUIDs[i]; + } + + _udonNodeData.flowUIDs = newFlowArray; + + _udonNodeData.flowUIDs.SetValue(newValue, _nodeValueIndex); + } + else + { + _udonNodeData.flowUIDs.SetValue(newValue, _nodeValueIndex); + } + } + + public bool IsReloading() + { + if (node is UdonNode) + { + return ((UdonNode) node).Graph.IsReloading; + } + else + { + return false; + } + } + + public void SetDataFromNewConnection(string uidAndPort, int index) + { + // can't do this for Reg stack nodes yet so skipping for demo + if (_udonNodeData == null) return; + + if (_udonNodeData.nodeUIDs.Length <= _nodeValueIndex) + { + Debug.Log("Couldn't set it"); + } + else + { + _udonNodeData.nodeUIDs.SetValue(uidAndPort, index); + } + } + + // Update elements on disconnect + public override void Disconnect(Edge edge) + { + RemoveFromClassList("connected"); + if (node == null) return; + Undo.RecordObject(((UdonNode)node).Graph.graphProgramAsset, "Connect Edge"); + base.Disconnect(edge); + + // hide label, show field + if (direction == Direction.Input) + { + UpdateLabel(false); + } + + if (IsReloading()) + { + return; + } + + // update data + if (direction == Direction.Output && portType == null) + { + // We are a flow port + SetFlowUID(""); + this.Compile(); + } + else if (direction == Direction.Input && portType != null) + { + // Direction is input + // We are a value port + SetDataFromNewConnection("", GetIndex()); + } + } + + public void UpdateLabel(bool isConnected) + { + // Port has a 'connected' bool but it doesn't seem to update, so passing 'isConnected' for now + + if (isConnected) + { + if (_inputField != null && Contains(_inputField)) + { + _inputField.RemoveFromHierarchy(); + } + + if (_inputFieldTypeLabel != null && !Contains(_inputFieldTypeLabel)) + { + Add(_inputFieldTypeLabel); + } + + if (_editArrayButton != null && Contains(_editArrayButton)) + { + _editArrayButton.RemoveFromHierarchy(); + } + } + else + { + if (_inputField != null && !Contains(_inputField)) + { + Add(_inputField); + } + + if (_inputFieldTypeLabel != null && Contains(_inputFieldTypeLabel)) + { + _inputFieldTypeLabel.RemoveFromHierarchy(); + } + + if (_editArrayButton != null && !Contains(_editArrayButton)) + { + Add(_editArrayButton); + } + } + } + + private bool TryGetValueObject(out object result, Type type = null) + { + // Initialize out object + result = null; + + // get container from node values + SerializableObjectContainer container = _udonNodeData.nodeValues[_nodeValueIndex]; + + // Null check, failure + if (container == null) + return false; + + // Deserialize into result, return failure on null + result = container.Deserialize(); + + // Strings will deserialize as null, that's ok + if (type == null || type == typeof(string)) + { + return true; + } + // any other type is not ok to be null + else if (result == null) + { + return false; + } + + // Success - return true + return type.IsInstanceOfType(result); + } + + private void SetNewValue(object newValue) + { + _udonNodeData.nodeValues[_nodeValueIndex] = SerializableObjectContainer.Serialize(newValue, portType); + } + } +} diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonPort.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonPort.cs.meta new file mode 100644 index 00000000..e09d6a0e --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonPort.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8f83d1d3578dd28498c71a980bca86dd +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonStackNode.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonStackNode.cs new file mode 100644 index 00000000..79baae39 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonStackNode.cs @@ -0,0 +1,6 @@ +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonStackNode + { + } +} \ No newline at end of file diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonStackNode.cs.meta b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonStackNode.cs.meta new file mode 100644 index 00000000..827649e8 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonStackNode.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 1d5984c5be753da439b8a33ffbee8d36 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonVariablesBlackboard.cs b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonVariablesBlackboard.cs new file mode 100644 index 00000000..1b59c5d3 --- /dev/null +++ b/VRCSDK3Worlds/Assets/Udon/Editor/ProgramSources/UdonGraphProgram/UI/GraphView/GraphElements/UdonVariablesBlackboard.cs @@ -0,0 +1,122 @@ +#if UNITY_2019_3_OR_NEWER +using UnityEngine.UIElements; +using UnityEditor.Experimental.GraphView; +#else +using UnityEngine.Experimental.UIElements; +using UnityEditor.Experimental.UIElements.GraphView; +#endif +using System.Collections.Generic; +using UnityEngine; +using VRC.Udon.Graph; + +namespace VRC.Udon.Editor.ProgramSources.UdonGraphProgram.UI.GraphView +{ + public class UdonVariablesBlackboard : Blackboard, IUdonGraphElementDataProvider + { + private CustomData _customData = new CustomData(); + private UdonGraph _graph; + private Dictionary _idToRow; + + public UdonVariablesBlackboard(UdonGraph graph) + { + _graph = graph; + title = "Variables"; + name = "Parameters"; + scrollable = true; + + // Remove subtitle + var subtitle = this.Query