Skip to content

Commit

Permalink
Merge pull request #329 from anatawa12/self-reference-stack-overflow
Browse files Browse the repository at this point in the history
Early circular dependency detection
  • Loading branch information
anatawa12 authored Aug 18, 2023
2 parents fc68da7 + 1d1bdf3 commit 3cb2c1c
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGELOG-PRERELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog].
### Removed

### Fixed
- Unity Editor may freezes when there are circular dependency `#329`

### Security

Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ The format is based on [Keep a Changelog].
### Removed

### Fixed
- Unity Editor may freezes when there are circular dependency `#329`

### Security

Expand Down
42 changes: 41 additions & 1 deletion Editor/EditSkinnedMeshComponentUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -173,10 +173,11 @@ private IMeshInfoComputer[] GetComputers()
{
if (_computers != null) return _computers;
var sorted = GetSorted();
_computers = new IMeshInfoComputer[sorted.Count + 1];
_computers = new IMeshInfoComputer[sorted.Count + 2];
var computer = _computers[0] = new SourceMeshInfoComputer(Target);
for (var i = 0; i < sorted.Count; i++)
computer = _computers[i + 1] = sorted[i].GetComputer(computer);
_computers[sorted.Count + 1] = new RecursiveDetector(computer);
return _computers;
}

Expand All @@ -188,6 +189,38 @@ private IMeshInfoComputer GetComputer(EditSkinnedMeshComponent before = null) =>

public Material[] GetMaterials(EditSkinnedMeshComponent before = null, bool fast = true) =>
GetComputer(before).Materials(fast);

private class RecursiveDetector : IMeshInfoComputer
{
private readonly IMeshInfoComputer _origin;

public RecursiveDetector(IMeshInfoComputer origin)
{
_origin = origin;
}

[ThreadStatic]
private static HashSet<RecursiveDetector> _currentThreadDetectors;

private T CheckRecursive<T>(Func<T> compute)
{
if (_currentThreadDetectors == null)
_currentThreadDetectors = new HashSet<RecursiveDetector>();
if (!_currentThreadDetectors.Add(this))
throw new RecursiveSkinnedMeshDependencyException();
try
{
return compute();
}
finally
{
_currentThreadDetectors.Remove(this);
}
}

public string[] BlendShapes() => CheckRecursive(() => _origin.BlendShapes());
public Material[] Materials(bool fast = true) => CheckRecursive(() => _origin.Materials(fast));
}
}

private static readonly Dictionary<Type, Func<EditSkinnedMeshComponent, IEditSkinnedMeshProcessor>> Creators =
Expand All @@ -203,4 +236,11 @@ public Material[] GetMaterials(EditSkinnedMeshComponent before = null, bool fast
private static IEditSkinnedMeshProcessor CreateProcessor(EditSkinnedMeshComponent mergePhysBone) =>
Creators[mergePhysBone.GetType()].Invoke(mergePhysBone);
}

internal class RecursiveSkinnedMeshDependencyException : Exception
{
public RecursiveSkinnedMeshDependencyException() : base("Recursive Dependencies Detected!")
{
}
}
}

0 comments on commit 3cb2c1c

Please sign in to comment.