Skip to content

Commit

Permalink
feat: add non-component-based hook execution deduplication (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
bdunderscore authored Jan 29, 2024
1 parent 4bce2ef commit 32e0155
Show file tree
Hide file tree
Showing 4 changed files with 57 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [unreleased]

### Added
- Added a non-component-based check for double execution of hooks (#142)

### Fixed

Expand Down
11 changes: 10 additions & 1 deletion Editor/VRChat/BuildFrameworkPreprocessHook.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,13 @@ internal class BuildFrameworkPreprocessHook : IVRCSDKPreprocessAvatarCallback

public bool OnPreprocessAvatar(GameObject avatarGameObject)
{
// Legacy: For VRCF
if (avatarGameObject.GetComponent<AlreadyProcessedTag>()?.processingCompleted == true) return true;

var state = HookDedup.RecordAvatar(avatarGameObject);
if (state.ranEarlyHook) return true;
state.ranEarlyHook = true;

try
{
var holder = avatarGameObject.AddComponent<ContextHolder>();
Expand All @@ -53,7 +58,11 @@ internal class BuildFrameworkOptimizeHook : IVRCSDKPreprocessAvatarCallback
public bool OnPreprocessAvatar(GameObject avatarGameObject)
{
if (avatarGameObject.GetComponent<AlreadyProcessedTag>()?.processingCompleted == true) return true;


var state = HookDedup.RecordAvatar(avatarGameObject);
if (state.ranOptimization) return true;
state.ranOptimization = true;

var holder = avatarGameObject.GetComponent<ContextHolder>();
if (holder == null) return true;

Expand Down
43 changes: 43 additions & 0 deletions Editor/VRChat/HookDedup.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#if NDMF_VRCSDK3_AVATARS

using System.Runtime.CompilerServices;
using UnityEngine;

namespace nadena.dev.ndmf.VRChat
{
/// <summary>
/// Ensures that we don't run hooks more than once. This is in preparation for coordinating with VRCFury to have all
/// nondestructive utilities independently execute hooks as part of Apply on Play, while deduplicating to ensure that
/// we don't rerun hooks on the same avatar.
/// </summary>
internal static class HookDedup
{
internal class State
{
internal bool ranEarlyHook;
internal bool ranOptimization;
}

private static ConditionalWeakTable<GameObject, State> _avatars = new ConditionalWeakTable<GameObject, State>();

public static State RecordAvatar(GameObject root)
{
if (_avatars.TryGetValue(root, out var state))
{
return state;
}

state = new State();
_avatars.Add(root, state);

return state;
}

public static bool HasAvatar(GameObject root)
{
return _avatars.TryGetValue(root, out _);
}
}
}

#endif
3 changes: 3 additions & 0 deletions Editor/VRChat/HookDedup.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 32e0155

Please sign in to comment.