Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,18 @@ internal Action QueueMaterialTextureFromFile(
// Track slot replacement without narrowing the caller's apply scope.
var location = FindGameObject(objectType, slot);
var target = new MaterialEditTarget(go, material, propertyName);
return _textureImports.Enqueue(target,
() => this != null && GetCoordinateIndex(objectType) == coordinate
var cancel = _textureImports.Enqueue(target,
() => this != null && isActiveAndEnabled && GetCoordinateIndex(objectType) == coordinate
&& FindGameObject(objectType, slot) == location
&& !CoordinateChanging && File.Exists(filePath),
done => { done(MaterialEditResult.FromApplied(
TrySetMaterialTextureFromFile(slot, objectType, material, propertyName, filePath, go))); return null; },
completed);
// A file-dialog callback can arrive after OnDisable stopped Update.
// Complete through the queue's normal cancellation path immediately.
if (!isActiveAndEnabled)
cancel?.Invoke();
return cancel;
}

private bool TrySetMaterialTextureFromFile(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -677,36 +677,31 @@ internal void HandleMaterialNameChange(int slot, ObjectType objectType, Renderer
}
}

private Coroutine _clothesMainTexRefresh;
private Coroutine _bodyMainTexRefresh;
private int _mainTexRefreshGeneration;

/// <summary>
/// Refresh the clothes MainTex, typically called after editing colors in the character maker
/// </summary>
private EndOfFrameRefreshGate _clothesMainTexRefreshGate;
private EndOfFrameRefreshGate _bodyMainTexRefreshGate;

public void RefreshClothesMainTex()
{
if (!_clothesMainTexRefreshGate.TryRequest())
{
if (!isActiveAndEnabled || _clothesMainTexRefresh != null)
return;
}
try
{
if (StartCoroutine(RefreshClothesMainTexCoroutine()) != null)
return;
}
catch
{
_clothesMainTexRefreshGate.Complete();
throw;
}
_clothesMainTexRefreshGate.Complete();

// A failed start leaves the handle null, so a later request can retry.
_clothesMainTexRefresh = StartCoroutine(
RefreshClothesMainTexCoroutine(_mainTexRefreshGeneration));
}

private IEnumerator RefreshClothesMainTexCoroutine()
private IEnumerator RefreshClothesMainTexCoroutine(int generation)
{
yield return new WaitForEndOfFrame();
try
{
yield return new WaitForEndOfFrame();
if (!isActiveAndEnabled || generation != _mainTexRefreshGeneration)
yield break;

for (var i = 0; i < MaterialTexturePropertyList.Count; i++)
{
var property = MaterialTexturePropertyList[i];
Expand All @@ -726,7 +721,8 @@ private IEnumerator RefreshClothesMainTexCoroutine()
}
finally
{
_clothesMainTexRefreshGate.Complete();
if (generation == _mainTexRefreshGeneration)
_clothesMainTexRefresh = null;
}
}

Expand Down Expand Up @@ -778,28 +774,21 @@ private bool SetTextureWithProperty(GameObject go, MaterialTextureProperty textu
/// </summary>
public void RefreshBodyMainTex()
{
if (!_bodyMainTexRefreshGate.TryRequest())
{
if (!isActiveAndEnabled || _bodyMainTexRefresh != null)
return;
}
try
{
if (StartCoroutine(RefreshBodyMainTexCoroutine()) != null)
return;
}
catch
{
_bodyMainTexRefreshGate.Complete();
throw;
}
_bodyMainTexRefreshGate.Complete();

_bodyMainTexRefresh = StartCoroutine(
RefreshBodyMainTexCoroutine(_mainTexRefreshGeneration));
}

private IEnumerator RefreshBodyMainTexCoroutine()
private IEnumerator RefreshBodyMainTexCoroutine(int generation)
{
yield return new WaitForEndOfFrame();
try
{
yield return new WaitForEndOfFrame();
if (!isActiveAndEnabled || generation != _mainTexRefreshGeneration)
yield break;

for (var i = 0; i < MaterialTexturePropertyList.Count; i++)
{
var property = MaterialTexturePropertyList[i];
Expand All @@ -812,9 +801,26 @@ private IEnumerator RefreshBodyMainTexCoroutine()
}
finally
{
_bodyMainTexRefreshGate.Complete();
if (generation == _mainTexRefreshGeneration)
_bodyMainTexRefresh = null;
}
}

private void CancelMainTexRefreshes()
{
// Invalidate before stopping: an old iterator's finally must not
// clear a refresh requested after this character is enabled again.
_mainTexRefreshGeneration++;
var clothesRefresh = _clothesMainTexRefresh;
var bodyRefresh = _bodyMainTexRefresh;
_clothesMainTexRefresh = null;
_bodyMainTexRefresh = null;
if (clothesRefresh != null)
StopCoroutine(clothesRefresh);
if (bodyRefresh != null)
StopCoroutine(bodyRefresh);
}

/// <summary>
/// Reapply all edits to the body and face
/// </summary>
Expand All @@ -823,22 +829,5 @@ public void RefreshBodyEdits()
if (CharacterLoading) return;
StartCoroutine(LoadData(false, false, false));
}
private struct EndOfFrameRefreshGate
{
private bool _pending;

internal bool TryRequest()
{
if (_pending)
return false;
_pending = true;
return true;
}

internal void Complete()
{
_pending = false;
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ protected override void OnReload(GameMode currentGameMode, bool maintainState)
/// </summary>
protected override void OnDestroy()
{
CancelMainTexRefreshes();
_textureImports.Dispose();
ChaControl targetControl = null;
GameObject targetRoot = null;
Expand Down Expand Up @@ -192,6 +193,12 @@ protected override void OnDestroy()
}
}

private void OnDisable()
{
CancelMainTexRefreshes();
_textureImports.CancelAll();
}

private bool CurrentUiTargetBelongsToThisController()
{
var retainedTarget = MaterialEditorUI.RetainedTargetGameObject;
Expand Down
Loading