Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

Commit

Permalink
Fix OnEnable, OnDisable, and OnDestroy running on proxies when they s…
Browse files Browse the repository at this point in the history
…houldn't

- Proxies were having their OnEnable, OnDisable, and OnDestroy events run on them since they were not in a state to be detected as proxies. Now disable events when running methods that may trigger the events. Reported by PhaxeNor.
  • Loading branch information
MerlinVR committed Oct 28, 2020
1 parent 09a1f05 commit 7dc62b6
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 31 deletions.
11 changes: 10 additions & 1 deletion Assets/UdonSharp/Editor/Editors/UdonSharpBehaviourEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -408,7 +408,16 @@ void CleanupProxy()

if (backingBehaviour == null)
{
UnityEngine.Object.DestroyImmediate(currentProxyBehaviour);
UdonSharpEditorUtility.SetIgnoreEvents(true);

try
{
UnityEngine.Object.DestroyImmediate(currentProxyBehaviour);
}
finally
{
UdonSharpEditorUtility.SetIgnoreEvents(false);
}
}
}
}
Expand Down
11 changes: 10 additions & 1 deletion Assets/UdonSharp/Editor/Editors/UdonSharpUndo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,16 @@ public static void DestroyImmediate(UdonSharpBehaviour behaviour)
if (udonBehaviour)
Undo.DestroyObjectImmediate(udonBehaviour);

Undo.DestroyObjectImmediate(behaviour);
UdonSharpEditorUtility.SetIgnoreEvents(true);

try
{
Undo.DestroyObjectImmediate(behaviour);
}
finally
{
UdonSharpEditorUtility.SetIgnoreEvents(false);
}
}

/// <summary>
Expand Down
10 changes: 8 additions & 2 deletions Assets/UdonSharp/Editor/UdonSharpEditorManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ void InjectEvent(System.Type behaviourType, string eventName)
InjectEvent(udonSharpBehaviourType, "OnDestroy");
}

// Add method for checking if events need to be skipped
InjectedMethods.shouldSkipEventsMethod = (Func<bool>)Delegate.CreateDelegate(typeof(Func<bool>), typeof(UdonSharpBehaviour).GetMethod("ShouldSkipEvents", BindingFlags.Static | BindingFlags.NonPublic));

// Patch GUI object field drawer
MethodInfo doObjectFieldMethod = typeof(EditorGUI).GetMethods(BindingFlags.Static | BindingFlags.NonPublic).FirstOrDefault(e => e.Name == "DoObjectField" && e.GetParameters().Length == 9);

Expand Down Expand Up @@ -188,12 +191,13 @@ static class InjectedMethods
public static Delegate validationDelegate;
public static MethodInfo objectValidatorMethod;
public static Func<UnityEngine.Object, UnityEngine.Object, bool> crossSceneRefCheckMethod;
public static Func<bool> shouldSkipEventsMethod;

public static bool EventInterceptor(UdonSharpBehaviour __instance)
{
if (UdonSharpEditorUtility.IsProxyBehaviour(__instance))
if (UdonSharpEditorUtility.IsProxyBehaviour(__instance) || shouldSkipEventsMethod())
return false;

return true;
}

Expand Down Expand Up @@ -360,6 +364,8 @@ static void OnChangePlayMode(PlayModeStateChange state)

static void RunAllUpdates(List<UdonBehaviour> allBehaviours = null)
{
UdonSharpEditorUtility.SetIgnoreEvents(false);

if (allBehaviours == null)
allBehaviours = GetAllUdonBehaviours();

Expand Down
110 changes: 85 additions & 25 deletions Assets/UdonSharp/Editor/UdonSharpEditorUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,16 @@ public static UdonSharpBehaviour FindProxyBehaviour(UdonBehaviour udonBehaviour,
{
CopyUdonToProxy(proxyBehaviour, proxySerializationPolicy);

proxyBehaviour.enabled = false;
SetIgnoreEvents(true);

try
{
proxyBehaviour.enabled = false;
}
finally
{
SetIgnoreEvents(false);
}

return proxyBehaviour;
}
Expand All @@ -253,7 +262,7 @@ public static UdonSharpBehaviour FindProxyBehaviour(UdonBehaviour udonBehaviour,
}

UdonSharpBehaviour[] behaviours = udonBehaviour.GetComponents<UdonSharpBehaviour>();

foreach (UdonSharpBehaviour udonSharpBehaviour in behaviours)
{
IUdonBehaviour backingBehaviour = GetBackingUdonBehaviour(udonSharpBehaviour);
Expand All @@ -263,7 +272,16 @@ public static UdonSharpBehaviour FindProxyBehaviour(UdonBehaviour udonBehaviour,

CopyUdonToProxy(udonSharpBehaviour, proxySerializationPolicy);

udonSharpBehaviour.enabled = false;
SetIgnoreEvents(true);

try
{
udonSharpBehaviour.enabled = false;
}
finally
{
SetIgnoreEvents(false);
}

return udonSharpBehaviour;
}
Expand Down Expand Up @@ -311,6 +329,20 @@ public static System.Type GetUdonSharpBehaviourType(UdonBehaviour udonBehaviour)
return ((UdonSharpProgramAsset)udonBehaviour.programSource).sourceCsScript.GetClass();
}

static FieldInfo _skipEventsField = null;

/// <summary>
/// Used to disable sending events to UdonSharpBehaviours for OnEnable, OnDisable, and OnDestroy since they are not always in a valid state to be recognized as proxies during these events.
/// </summary>
/// <param name="ignore"></param>
internal static void SetIgnoreEvents(bool ignore)
{
if (_skipEventsField == null)
_skipEventsField = typeof(UdonSharpBehaviour).GetField("_skipEvents", BindingFlags.Static | BindingFlags.NonPublic);

_skipEventsField.SetValue(null, ignore);
}

/// <summary>
/// Gets the C# version of an UdonSharpBehaviour that proxies an UdonBehaviour with the program asset for the matching UdonSharpBehaviour type
/// </summary>
Expand Down Expand Up @@ -342,13 +374,22 @@ public static UdonSharpBehaviour GetProxyBehaviour(UdonBehaviour udonBehaviour,
if (scriptType == null)
return null;

proxyBehaviour = (UdonSharpBehaviour)udonBehaviour.gameObject.AddComponent(scriptType);
proxyBehaviour.hideFlags = HideFlags.DontSaveInBuild |
SetIgnoreEvents(true);

try
{
proxyBehaviour = (UdonSharpBehaviour)udonBehaviour.gameObject.AddComponent(scriptType);
proxyBehaviour.hideFlags = HideFlags.DontSaveInBuild |
#if !UDONSHARP_DEBUG
HideFlags.HideInInspector |
#endif
HideFlags.DontSaveInEditor;
proxyBehaviour.enabled = false;
proxyBehaviour.enabled = false;
}
finally
{
SetIgnoreEvents(false);
}

SetBackingUdonBehaviour(proxyBehaviour, udonBehaviour);

Expand Down Expand Up @@ -460,7 +501,17 @@ public static void DestroyImmediate(UdonSharpBehaviour behaviour)
if (backingBehaviour)
{
_proxyBehaviourLookup.Remove(backingBehaviour);
Object.DestroyImmediate(backingBehaviour);

SetIgnoreEvents(true);

try
{
Object.DestroyImmediate(backingBehaviour);
}
finally
{
SetIgnoreEvents(false);
}
}
}

Expand Down Expand Up @@ -653,33 +704,42 @@ internal static UdonBehaviour[] ConvertToUdonBehavioursInternal(UdonSharpBehavio

UdonSharpBehaviour newProxy;

if (shouldUndo)
newProxy = (UdonSharpBehaviour)Undo.AddComponent(targetObject.gameObject, behaviourType);
else
newProxy = (UdonSharpBehaviour)targetObject.gameObject.AddComponent(behaviourType);
SetIgnoreEvents(true);

UdonSharpEditorUtility.SetBackingUdonBehaviour(newProxy, udonBehaviour);
try
{
UdonSharpEditorUtility.CopyUdonToProxy(newProxy);
}
catch (System.Exception e)
{
Debug.LogError(e);
}

if (shouldUndo)
Undo.DestroyObjectImmediate(targetObject);
else
Object.DestroyImmediate(targetObject);
if (shouldUndo)
newProxy = (UdonSharpBehaviour)Undo.AddComponent(targetObject.gameObject, behaviourType);
else
newProxy = (UdonSharpBehaviour)targetObject.gameObject.AddComponent(behaviourType);

newProxy.hideFlags = HideFlags.DontSaveInBuild |
UdonSharpEditorUtility.SetBackingUdonBehaviour(newProxy, udonBehaviour);
try
{
UdonSharpEditorUtility.CopyUdonToProxy(newProxy);
}
catch (System.Exception e)
{
Debug.LogError(e);
}

if (shouldUndo)
Undo.DestroyObjectImmediate(targetObject);
else
Object.DestroyImmediate(targetObject);

newProxy.hideFlags = HideFlags.DontSaveInBuild |
#if !UDONSHARP_DEBUG
HideFlags.HideInInspector |
#endif
HideFlags.DontSaveInEditor;

newProxy.enabled = false;
newProxy.enabled = false;
}
finally
{
SetIgnoreEvents(false);
}

createdComponents.Add(udonBehaviour);
}
Expand Down
8 changes: 6 additions & 2 deletions Assets/UdonSharp/Scripts/UdonSharpBehaviour.cs
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,15 @@ public virtual void OnVideoReady() { }
public virtual void OnVideoStart() { }
public virtual void OnPreSerialization() { }
public virtual void OnDeserialization() { }
#if UDON_BETA_SDK || true
//public virtual bool OnOwnershipRequest(VRC.SDKBase.VRCPlayerApi requestingPlayer, VRC.SDKBase.VRCPlayerApi requestedOwner) => true;
public virtual void OnPlayerTriggerEnter(VRC.SDKBase.VRCPlayerApi player) { }
public virtual void OnPlayerTriggerExit(VRC.SDKBase.VRCPlayerApi player) { }
public virtual void OnPlayerTriggerStay(VRC.SDKBase.VRCPlayerApi player) { }
public virtual void OnPlayerCollisionEnter(VRC.SDKBase.VRCPlayerApi player) { }
public virtual void OnPlayerCollisionExit(VRC.SDKBase.VRCPlayerApi player) { }
public virtual void OnPlayerCollisionStay(VRC.SDKBase.VRCPlayerApi player) { }
public virtual void OnPlayerParticleCollision(VRC.SDKBase.VRCPlayerApi player) { }
#if UDON_BETA_SDK
public virtual bool OnOwnershipRequest(VRC.SDKBase.VRCPlayerApi requestingPlayer, VRC.SDKBase.VRCPlayerApi requestedOwner) => true;
#endif

[Obsolete("The OnStationEntered() event is deprecated use the OnStationEntered(VRCPlayerApi player) event instead, this event will be removed in a future release.")]
Expand Down Expand Up @@ -164,7 +164,11 @@ void ISerializationCallbackReceiver.OnAfterDeserialize()
#pragma warning disable CS0414 // Referenced via reflection
[SerializeField, HideInInspector]
private bool _isValidForAutoCopy = false;

private static bool _skipEvents = false;
#pragma warning restore CS0414

private static bool ShouldSkipEvents() => _skipEvents;
#endif
}
}

0 comments on commit 7dc62b6

Please sign in to comment.