private static void SetVariable <T>(UdonBehaviour behaviour, string variableKey, T value) { System.Type type = typeof(T); bool isNull = false; if ((value is UnityEngine.Object unityEngineObject && unityEngineObject == null) || value == null) { isNull = true; } if (isNull) { bool isRemoveType = (type == typeof(GameObject) || type == typeof(Transform) || type == typeof(UdonBehaviour)); if (isRemoveType) { behaviour.publicVariables.RemoveVariable(variableKey); } else { SetVarInternal <T>(behaviour, variableKey, value); } } else { SetVarInternal <T>(behaviour, variableKey, value); } }
private static T GetVariable <T>(UdonBehaviour behaviour, string variableKey) { T output; if (behaviour.publicVariables.TryGetVariableValue <T>(variableKey, out output)) { return(output); } // The type no longer matches exactly, but is trivially convertible // This will usually flow into a reassignment of the public variable type in SetVarInternal() when the value gets copied back to Udon if (behaviour.publicVariables.TryGetVariableValue(variableKey, out object outputObj) && !outputObj.IsUnityObjectNull() && outputObj is T) { return((T)outputObj); } // Try to get the default value if there's no custom value specified if (behaviour.programSource != null && behaviour.programSource is UdonSharpProgramAsset udonSharpProgramAsset) { udonSharpProgramAsset.UpdateProgram(); IUdonProgram program = udonSharpProgramAsset.GetRealProgram(); uint varAddress; if (program.SymbolTable.TryGetAddressFromSymbol(variableKey, out varAddress)) { if (program.Heap.TryGetHeapVariable <T>(varAddress, out output)) { return(output); } } } return(default);
void Start() { _EventManger = (UdonBehaviour)GameObject.Find("[SE_Manager]").GetComponent(typeof(UdonBehaviour)); UdonBehaviour master = (UdonBehaviour)transform.parent.GetComponent(typeof(UdonBehaviour)); master.SetProgramVariable("EventHandler", this); }
void ProcessPayload() { Component[] receiverComponents = transform.parent.GetComponents(typeof(UdonBehaviour)); int componentIndex = System.Int32.Parse((string)EVENT_ARRAY.GetValue(2)); if (componentIndex < receiverComponents.GetLowerBound(0) || componentIndex > receiverComponents.GetUpperBound(0)) { Debug.Log("[SE_Handler] Error: Component index " + componentIndex + " is out of bounds"); return; } UdonBehaviour receiverUdon = (UdonBehaviour)receiverComponents.GetValue(componentIndex); if (receiverUdon == null) { Debug.Log("[SE_Handler] Error: Could not access UdonBehaviour at index " + componentIndex); return; } if (EVENT_ARRAY.Length == 6) { string parametersString = (string)EVENT_ARRAY.GetValue(5); string[] parametersArray = parametersString.Split('|'); receiverUdon.SetProgramVariable("PARAMS", parametersArray); } string udonEventName = (string)EVENT_ARRAY.GetValue(4); receiverUdon.SendCustomEvent(udonEventName); }
public static UdonSharpBehaviour AddUdonSharpComponent(this GameObject gameObject, System.Type type) { if (type == typeof(UdonSharpBehaviour)) { throw new System.ArgumentException("Cannot add components of type 'UdonSharpBehaviour', you can only add subclasses of this type"); } if (!typeof(UdonSharpBehaviour).IsAssignableFrom(type)) { throw new System.ArgumentException("Type for AddUdonSharpComponent must be a subclass of UdonSharpBehaviour"); } UdonBehaviour udonBehaviour = gameObject.AddComponent <UdonBehaviour>(); UdonSharpProgramAsset programAsset = UdonSharpProgramAsset.GetProgramAssetForClass(type); udonBehaviour.programSource = programAsset; udonBehaviour.AllowCollisionOwnershipTransfer = false; SerializedObject componentAsset = new SerializedObject(udonBehaviour); SerializedProperty serializedProgramAssetProperty = componentAsset.FindProperty("serializedProgramAsset"); serializedProgramAssetProperty.objectReferenceValue = programAsset.SerializedProgramAsset; componentAsset.ApplyModifiedPropertiesWithoutUndo(); UdonSharpBehaviour proxyComponent = UdonSharpEditorUtility.GetProxyBehaviour(udonBehaviour); if (EditorApplication.isPlaying) { udonBehaviour.InitializeUdonContent(); } return(proxyComponent); }
public static void SendCustomNetworkEventHook(UdonBehaviour behaviour, NetworkEventTarget target, string eventName) { if (string.IsNullOrEmpty(eventName)) { return; } if (eventName[0] == '_') { behaviour.LogError("Did not send custom network event \"" + eventName + "\". Events starting " + "with an underscore may not be run remotely. " + VRC.Tools.GetGameObjectPath(behaviour.gameObject)); return; } if (target == NetworkEventTarget.All || (target == NetworkEventTarget.Owner && Networking.IsOwner(behaviour.gameObject))) { behaviour.Log("Sending Network Event! eventName:" + eventName + ", obj:" + VRC.Tools.GetGameObjectPath(behaviour.gameObject)); behaviour.SendCustomEvent(eventName); } else { behaviour.LogWarning("Did not send custom network event " + eventName + " for object at " + VRC.Tools.GetGameObjectPath(behaviour.gameObject)); } }
private static T GetVariable <T>(UdonBehaviour behaviour, string variableKey) { T output; if (behaviour.publicVariables.TryGetVariableValue <T>(variableKey, out output)) { return(output); } // Try to get the default value if there's no custom value specified if (behaviour.programSource != null && behaviour.programSource is UdonSharpProgramAsset udonSharpProgramAsset) { udonSharpProgramAsset.UpdateProgram(); IUdonProgram program = udonSharpProgramAsset.GetRealProgram(); uint varAddress; if (program.SymbolTable.TryGetAddressFromSymbol(variableKey, out varAddress)) { if (program.Heap.TryGetHeapVariable <T>(varAddress, out output)) { return(output); } } } return(default);
protected override void DrawProgramSourceGUI(UdonBehaviour udonBehaviour, ref bool dirty) { DrawAssemblyTextArea(!Application.isPlaying, ref dirty); DrawAssemblyErrorTextArea(); base.DrawProgramSourceGUI(udonBehaviour, ref dirty); }
/// <summary> /// checks whether the current value of a variable is null (not nullable types return false) /// </summary> /// <param name="udonBehaviour"></param> /// <param name="symbolName"></param> /// <param name="variableType"></param> /// <returns></returns> /// <exception cref="ArgumentException">if udonBehaviour is invalid</exception> public static bool IsInspectorVariableNull(this UdonBehaviour udonBehaviour, string symbolName, out Type variableType) { udonBehaviour.GetInspectorVariable(symbolName, out var variableValue, out variableType); return(variableType.IsNullable() && variableValue.IsUnityObjectNull()); }
void GetEmitter() { if (LocalPlayerApi != null) { if (LocalPlayerApi.isMaster) { UdonBehaviour emitterUdon = (UdonBehaviour)Emitters.transform.GetChild(0).GetComponent(typeof(UdonBehaviour)); LocallyOwnedEmitter = emitterUdon; return; } else { int emitterCount = Emitters.transform.childCount; for (int i = 1; i < emitterCount; i++) { UdonBehaviour emitterUdon = (UdonBehaviour)Emitters.transform.GetChild(i).GetComponent(typeof(UdonBehaviour)); if (Networking.GetOwner(emitterUdon.gameObject).isMaster) { Networking.SetOwner(LocalPlayerApi, emitterUdon.gameObject); LocallyOwnedEmitter = emitterUdon; return; } } } } else { UdonBehaviour emitter = (UdonBehaviour)Emitters.transform.GetChild(0).GetComponent(typeof(UdonBehaviour)); emitter.SetProgramVariable("Owner", "UNITY_EDITOR"); LocallyOwnedEmitter = emitter; return; } }
private void ShowVariableEditor(UdonBehaviour udonBehaviour) { expandVariableEditor_ = EditorGUILayout.Foldout(expandVariableEditor_, "Edit Public Variables", true); if (!expandVariableEditor_) { return; } var program = udonBehaviour.programSource; if (!(program is UdonProgramAsset programAsset)) { return; } var publicVariables = udonBehaviour.publicVariables; foreach (var varName in publicVariables.VariableSymbols) { publicVariables.TryGetVariableType(varName, out Type varType); object value = udonBehaviour.GetProgramVariable(varName); object[] parameters = { varName, value, varType, false, true }; var res = DrawPropertyMethod.Invoke(programAsset, parameters); if ((bool)parameters[3]) { udonBehaviour.SetProgramVariable(varName, res); } } }
// リセット public void Reset() { selected = 0; state = 0; targetik = true; character.Emote(0, 0f); // 表情変更 なし character.Move3(Vector3.zero, 0); // アニメーション停止 agent.transform.position = _rusk_home_point.position; // おうちに瞬間移動 agent.SetDestination(agent.transform.position); ashioto(false); for (var i = 0; i < _tgroot.transform.childCount; i++) { GameObject ball = _tgroot.transform.GetChild(i).gameObject; if (ball != null && ball.activeSelf) { UdonBehaviour udon = (UdonBehaviour)ball.GetComponent(typeof(UdonBehaviour)); if (udon != null) { udon.SendCustomEvent("BallReset"); // ボール状態リセット } } } }
// Returns true if the serializedProgramProperty was changed, false otherwise. private static bool PopulateSerializedProgramAssetReference(UdonBehaviour udonBehaviour) { SerializedObject serializedUdonBehaviour = new SerializedObject(udonBehaviour); SerializedProperty programSourceSerializedProperty = serializedUdonBehaviour.FindProperty("programSource"); SerializedProperty serializedProgramAssetSerializedProperty = serializedUdonBehaviour.FindProperty("serializedProgramAsset"); if (!(programSourceSerializedProperty.objectReferenceValue is AbstractUdonProgramSource abstractUdonProgramSource)) { return(false); } if (abstractUdonProgramSource == null) { return(false); } if (serializedProgramAssetSerializedProperty.objectReferenceValue == abstractUdonProgramSource.SerializedProgramAsset) { return(false); } serializedProgramAssetSerializedProperty.objectReferenceValue = abstractUdonProgramSource.SerializedProgramAsset; serializedUdonBehaviour.ApplyModifiedPropertiesWithoutUndo(); return(true); }
private static List <(UdonBehaviour, string)> CollectListenerReferences(UdonBehaviour currentBehaviour, object @return) { var callers = new List <(UdonBehaviour, string)>(); var rootObjects = SceneManager.GetActiveScene().GetRootGameObjects(); var components = new List <UdonBehaviour>(); foreach (var o in rootObjects) { components.AddRange(o.GetComponentsInChildren <UdonBehaviour>().Where(UdonSharpEditorUtility.IsUdonSharpBehaviour)); } foreach (var behaviour in components) { var publicVariables = behaviour.publicVariables; if (publicVariables == null || publicVariables.VariableSymbols.Count == 0) { continue; } foreach (var s in publicVariables.VariableSymbols) { if (publicVariables.TryGetVariableValue(s, out var obj) && obj is Object o && o == (Object)@return && behaviour != currentBehaviour) { callers.Add((behaviour, s)); break; } } } return(callers); }
public override void OnInspectorGUI() { base.OnInspectorGUI(); CyanEmuUdonHelper udonHelper = target as CyanEmuUdonHelper; CyanEmuSyncableEditorHelper.DisplaySyncOptions(udonHelper); UdonBehaviour udonBehaviour = udonHelper.GetUdonBehaviour(); // TODO set public variables expand_ = EditorGUILayout.Foldout(expand_, "Run Custom Event"); if (expand_) { foreach (string eventName in udonBehaviour.GetPrograms()) { if (GUILayout.Button(eventName)) { udonBehaviour.SendCustomEvent(eventName); } } } }
private static (bool, List <Attribute>) ShouldRunValidator(UdonBehaviour currentBehaviour, string symbol, Type variableType, object @return) { if (@return == null || variableType != typeof(UdonBehaviour)) { return(false, null); } if (!UdonSharpEditorUtility.IsUdonSharpBehaviour(currentBehaviour)) { return(false, null); } if (UdonSharpProgramAsset.GetBehaviourClass((UdonBehaviour)@return) != typeof(EventListener)) { return(false, null); } var proxyBehaviour = UdonSharpEditorUtility.GetProxyBehaviour(currentBehaviour); var variable = proxyBehaviour.GetType().GetField(symbol, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (variable == null) { return(false, null); } var attrs = Validators.Select(validator => variable.GetCustomAttribute(validator)).Where(attr => attr != null).ToList(); return(attrs.Count == 0 ? (false, null) : (true, attrs)); }
/// <summary> /// </summary> /// <param name="udonBehaviour"></param> /// <returns></returns> /// <exception cref="Exception">if the UdonBehaviour has no public variables</exception> private static IUdonSymbolTable GetSymbolTable(this UdonBehaviour udonBehaviour) { if (!udonBehaviour || !(udonBehaviour.programSource is UdonSharpProgramAsset)) { throw new Exception("ProgramSource is not an UdonSharpProgramAsset"); } var programAsset = (UdonSharpProgramAsset)udonBehaviour.programSource; if (!programAsset) { throw new Exception("UdonBehaviour has no UdonSharpProgramAsset"); } programAsset.UpdateProgram(); var program = programAsset.GetRealProgram(); if (program?.SymbolTable == null) { throw new Exception("UdonBehaviour has no public variables"); } return(program.SymbolTable); }
public void InitializeGraph(UdonGraphProgramAsset graph, UdonBehaviour udonBehaviour = null) { this._graphAsset = graph; InitializeWindow(); _graphView = _rootView.Children().FirstOrDefault(e => e is UdonGraph) as UdonGraph; if (_graphView == null) { Debug.LogError("GraphView has not been added to the BaseGraph root view!"); return; } _graphView.Initialize(graph, udonBehaviour); _graphStatus.LoadAsset(graph); // Store GUID for this asset to settings for easy reload later if (AssetDatabase.TryGetGUIDAndLocalFileIdentifier(graph, out string guid, out long localId)) { Settings.LastGraphGuid = guid; } if (udonBehaviour != null) { Settings.LastUdonBehaviourPath = udonBehaviour.transform.GetHierarchyPath(); Settings.LastUdonBehaviourScenePath = udonBehaviour.gameObject.scene.path; } _graphAssetName.text = graph.name; ShowGraphTools(true); }
/// <summary> /// Finds an existing proxy behaviour, if none exists returns null /// </summary> /// <param name="udonBehaviour"></param> /// <returns></returns> private static UdonSharpBehaviour FindProxyBehaviour_Internal(UdonBehaviour udonBehaviour) { if (_proxyBehaviourLookup.TryGetValue(udonBehaviour, out UdonSharpBehaviour proxyBehaviour)) { if (proxyBehaviour != null) { return(proxyBehaviour); } _proxyBehaviourLookup.Remove(udonBehaviour); } UdonSharpBehaviour[] behaviours = udonBehaviour.GetComponents <UdonSharpBehaviour>(); foreach (UdonSharpBehaviour udonSharpBehaviour in behaviours) { IUdonBehaviour backingBehaviour = GetBackingUdonBehaviour(udonSharpBehaviour); if (backingBehaviour != null && ReferenceEquals(backingBehaviour, udonBehaviour)) { _proxyBehaviourLookup.Add(udonBehaviour, udonSharpBehaviour); return(udonSharpBehaviour); } } return(null); }
internal static void SetBehaviourVersion(UdonBehaviour behaviour, UdonSharpBehaviourVersion version) { UdonSharpBehaviourVersion lastVer = GetBehaviourVersion(behaviour); if (lastVer == version && lastVer != UdonSharpBehaviourVersion.V0) { return; } bool setVer = behaviour.publicVariables.TrySetVariableValue <int>(UDONSHARP_BEHAVIOUR_VERSION_KEY, (int)version); if (!setVer) { behaviour.publicVariables.RemoveVariable(UDONSHARP_BEHAVIOUR_VERSION_KEY); IUdonVariable newVar = new UdonVariable <int>(UDONSHARP_BEHAVIOUR_VERSION_KEY, (int)version); setVer = behaviour.publicVariables.TryAddVariable(newVar); } if (setVer) { UdonSharpUtils.SetDirty(behaviour); return; } UdonSharpUtils.LogError("Could not set version variable"); }
// Allow people to drag program assets onto objects in the scene and automatically create a corresponding UdonBehaviour with everything set up // https://forum.unity.com/threads/drag-and-drop-scriptable-object-to-scene.546975/#post-4534333 void OnSceneDrag(SceneView sceneView) { Event e = Event.current; GameObject gameObject = HandleUtility.PickGameObject(e.mousePosition, false); if (e.type == EventType.DragUpdated) { if (gameObject) { DragAndDrop.visualMode = DragAndDropVisualMode.Link; } else { DragAndDrop.visualMode = DragAndDropVisualMode.Rejected; } e.Use(); } else if (e.type == EventType.DragPerform) { DragAndDrop.AcceptDrag(); e.Use(); if (gameObject) { UdonBehaviour component = Undo.AddComponent <UdonBehaviour>(gameObject); component.programSource = target as UdonSharpProgramAsset; } } }
public static UdonSharpBehaviour GetUdonBehaviour(Type udonSharpType, GameObject gameObject) { UdonBehaviour adapter = gameObject.GetComponents <UdonBehaviour>().Where(udon => udon.programSource != null && udon.programSource.GetType() == typeof(UdonSharpProgramAsset) && (udon.programSource as UdonSharpProgramAsset).sourceCsScript.GetClass() == udonSharpType).FirstOrDefault(); if (adapter != null) { return(UdonSharpEditorUtility.GetProxyBehaviour(adapter)); } adapter = gameObject.GetComponents <UdonBehaviour>().Where(udon => udon.programSource == null).FirstOrDefault(); if (adapter == null) { adapter = gameObject.AddComponent <UdonBehaviour>(); } string[] guids = AssetDatabase.FindAssets(udonSharpType.Name + " t:UdonSharpProgramAsset"); if (guids.Length > 0) { UdonSharpProgramAsset udonProgram = (UdonSharpProgramAsset)AssetDatabase.LoadMainAssetAtPath(AssetDatabase.GUIDToAssetPath(guids[0])); if (udonProgram != null && udonProgram.GetSerializedUdonProgramAsset() != null) { adapter.AssignProgramAndVariables(udonProgram.GetSerializedUdonProgramAsset(), new VRC.Udon.Common.UdonVariableTable()); adapter.programSource = udonProgram; UdonSharpEditorUtility.GetProxyBehaviour(adapter); } } return(UdonSharpEditorUtility.GetProxyBehaviour(adapter)); }
private void updatePlayers() { if (playerObserverUdon == null) { playerObserverUdon = (UdonBehaviour)playerObserver.GetComponent(typeof(UdonBehaviour)); } var allPlayers = (VRCPlayerApi[])playerObserverUdon.GetProgramVariable("Players"); if (allPlayers == null) { return; } var isModified = false; var halfScale = transform.localScale / 2; var zMin = transform.position.z - halfScale.z; var zMax = transform.position.z + halfScale.z; var xMin = transform.position.x - halfScale.x; var xMax = transform.position.x + halfScale.x; int k = 0; for (int i = 0; i < allPlayers.Length; i++) { var player = allPlayers[i]; if (player == null) { break; } var ppos = player.GetPosition(); var isInArea = zMin < ppos.z && ppos.z < zMax && xMin < ppos.x && ppos.x < xMax; if (isInArea) { if (Players[k] == null || Players[k].playerId != player.playerId) { isModified = true; } Players[k++] = player; } } for (; k < Players.Length; k++) { if (Players[k] == null) { break; } Players[k] = null; isModified = true; } if (isModified) { updateText(); emitModifyEvent(); } }
public static UdonSharpBehaviour GetProxyBehaviour(UdonBehaviour udonBehaviour, ProxySerializationPolicy proxySerializationPolicy) { if (udonBehaviour == null) { throw new System.ArgumentNullException("Source Udon Behaviour cannot be null"); } if (udonBehaviour.programSource == null) { throw new System.ArgumentNullException("Program source on UdonBehaviour cannot be null"); } UdonSharpProgramAsset udonSharpProgram = udonBehaviour.programSource as UdonSharpProgramAsset; if (udonSharpProgram == null) { throw new System.ArgumentException("UdonBehaviour must be using an UdonSharp program"); } UdonSharpBehaviour proxyBehaviour = FindProxyBehaviour(udonBehaviour, proxySerializationPolicy); if (proxyBehaviour) { return(proxyBehaviour); } // We've failed to find an existing proxy behaviour so we need to create one System.Type scriptType = udonSharpProgram.GetClass(); if (scriptType == null) { return(null); } SetIgnoreEvents(true); try { proxyBehaviour = (UdonSharpBehaviour)udonBehaviour.gameObject.AddComponent(scriptType); proxyBehaviour.hideFlags = HideFlags.DontSaveInBuild | #if !UDONSHARP_DEBUG HideFlags.HideInInspector | #endif HideFlags.DontSaveInEditor; proxyBehaviour.enabled = false; } finally { SetIgnoreEvents(false); } SetBackingUdonBehaviour(proxyBehaviour, udonBehaviour); _proxyBehaviourLookup.Add(udonBehaviour, proxyBehaviour); CopyUdonToProxy(proxyBehaviour, proxySerializationPolicy); return(proxyBehaviour); }
void Start() { // 親オブジェクトを取得 parent = transform.parent.gameObject; // 親オブジェクトのU#スクリプトを取得 script = (UdonBehaviour)parent.GetComponent(typeof(UdonBehaviour)); }
public static UdonBehaviour CreateBehaviourForProxy(UdonSharpBehaviour udonSharpBehaviour) { UdonBehaviour backingBehaviour = GetBackingUdonBehaviour(udonSharpBehaviour); CopyProxyToUdon(udonSharpBehaviour); return(backingBehaviour); }
public static void OnInit(UdonBehaviour behaviour, IUdonProgram program) { CyanEmuUdonHelper helper = behaviour.gameObject.AddComponent <CyanEmuUdonHelper>(); helper.SetUdonBehaviour(behaviour); NetworkReadyFieldInfo_.SetValue(behaviour, CyanEmuMain.IsNetworkReady()); }
void OnPlayerLeft(VRCPlayerApi leftPlayer) { if (LocalPlayerApi.isMaster) { Debug.Log("Im Master Now!"); UdonBehaviour emitterUdon = (UdonBehaviour)Emitters.transform.GetChild(0).GetComponent(typeof(UdonBehaviour)); LocallyOwnedEmitter = emitterUdon; } }
private static bool IsSenderSupportRequestedEvents(UdonBehaviour behaviour, string s, SyntaxNode node, SemanticModel model, ISymbol symbol, out string @event) { var(n, m) = CreateAnalysisModels(behaviour); var declarationSymbol = FindEventListenerVariableDeclarationSyntax(n, m, s); var callee = n.DescendantNodes().OfType <InvocationExpressionSyntax>().Select(w => w.Expression).Where(w => { if (!(w is MemberAccessExpressionSyntax syntax)) { return(false); } var c = m.GetSymbolInfo(syntax.Expression); return(declarationSymbol.Equals(c.Symbol)); }).Cast <MemberAccessExpressionSyntax>().ToList(); if (callee.Count == 0) { @event = null; return(true); } var requestEvents = callee.Select(w => w.Name.Identifier.Text) .Distinct() .Where(w => MethodCorrespondenceTable.ContainsKey(w)) .Select(w => MethodCorrespondenceTable[w]) .Where(w => !string.IsNullOrWhiteSpace(w)) .OrderBy(w => w) .ToList(); var callers = node.DescendantNodes().OfType <InvocationExpressionSyntax>().Select(w => w.Expression).Where(w => { if (!(w is MemberAccessExpressionSyntax syntax)) { return(false); } var c = model.GetSymbolInfo(syntax.Expression); return(symbol.Equals(c.Symbol)); }).Cast <MemberAccessExpressionSyntax>(); var emitEvents = callers.Select(w => w.Name.Identifier.Text) .Distinct() .OrderBy(w => w) .ToList(); var missing = requestEvents.Except(emitEvents).ToList(); if (!missing.Any()) { @event = null; return(true); } @event = missing.First(); return(false); }
public override void OnInspectorGUI() { EditorGUILayout.HelpBox("Udon Sharp Behaviours need to be converted to Udon Behaviours to work in game. Click the convert button below to automatically convert the script.", MessageType.Warning); if (GUILayout.Button("Convert to UdonBehaviour", GUILayout.Height(25))) { Undo.RegisterCompleteObjectUndo(targets.Select(e => (e as MonoBehaviour)).Distinct().ToArray(), "Convert to UdonBehaviour"); foreach (Object targetObject in targets.Distinct()) { MonoScript behaviourScript = MonoScript.FromMonoBehaviour(targetObject as MonoBehaviour); UdonSharpProgramAsset programAsset = GetUdonSharpProgram(behaviourScript); if (programAsset == null) { string scriptPath = AssetDatabase.GetAssetPath(behaviourScript); string scriptDirectory = Path.GetDirectoryName(scriptPath); string scriptFileName = Path.GetFileNameWithoutExtension(scriptPath); string assetPath = Path.Combine(scriptDirectory, $"{scriptFileName}.asset").Replace('\\', '/'); if (AssetDatabase.LoadAssetAtPath <UdonSharpProgramAsset>(assetPath) != null) { if (!EditorUtility.DisplayDialog("Existing file found", $"Asset file {assetPath} already exists, do you want to overwrite it?", "Ok", "Cancel")) { continue; } } programAsset = ScriptableObject.CreateInstance <UdonSharpProgramAsset>(); programAsset.sourceCsScript = behaviourScript; programAsset.CompileCsProgram(); AssetDatabase.CreateAsset(programAsset, assetPath); AssetDatabase.SaveAssets(); AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport); } GameObject targetGameObject = (targetObject as MonoBehaviour).gameObject; Undo.DestroyObjectImmediate(targetObject); UdonBehaviour udonBehaviour = targetGameObject.AddComponent <UdonBehaviour>(); udonBehaviour.programSource = programAsset; Undo.RegisterCreatedObjectUndo(udonBehaviour, "Convert to UdonBehaviour"); } return; } EditorGUILayout.Space(); base.OnInspectorGUI(); }