diff --git a/Assets/ResourcesData/Character/@003_치요/Prop/편지지/Letter.mat b/Assets/ResourcesData/Character/@003_치요/Prop/편지지/Letter.mat
index 68c14fda1..4587d8b39 100644
--- a/Assets/ResourcesData/Character/@003_치요/Prop/편지지/Letter.mat
+++ b/Assets/ResourcesData/Character/@003_치요/Prop/편지지/Letter.mat
@@ -675,8 +675,8 @@ Material:
- _ColorRenderStatesGroup: 0
- _ColorRenderStatesGroupPreset: 0
- _ControlledByNiloToonPerCharacterRenderController: 0
- - _Cull: 2
- - _CullNiloToonSelfShadowCaster: 1
+ - _Cull: 0
+ - _CullNiloToonSelfShadowCaster: 0
- _CullOutline: 1
- _Cutoff: 0.5
- _DebugFaceShadowGradientMap: 0
@@ -1058,7 +1058,7 @@ Material:
- _ReceiveURPShadowMappingAmountForNonFace: 1
- _RenderCharacter: 1
- _RenderFaceGroup: 0
- - _RenderFacePreset: 0
+ - _RenderFacePreset: 2
- _RenderOutline: 1
- _RenderScreenSpaceOutline: 0
- _RenderScreenSpaceOutlineV2: 0
diff --git a/Assets/ResourcesData/Project/260605_치요님방송/260605_치요님방송_학교옥상.unity b/Assets/ResourcesData/Project/260605_치요님방송/260605_치요님방송_학교옥상.unity
index 7eb66bfe4..5851d65eb 100644
--- a/Assets/ResourcesData/Project/260605_치요님방송/260605_치요님방송_학교옥상.unity
+++ b/Assets/ResourcesData/Project/260605_치요님방송/260605_치요님방송_학교옥상.unity
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:b9c6d191978faaa1e43a3ecee8724e397b560c53045352bfd28d8d42f06e210f
-size 417309
+oid sha256:76fb7d0f23c90e994f4455c12f3feb9de70a2e6ae41a4c67c5653a3a511cdced
+size 436391
diff --git a/Assets/Scripts/Streamingle/DonationThrowable/ThrowableObject.cs b/Assets/Scripts/Streamingle/DonationThrowable/ThrowableObject.cs
index 502b16d6b..0c5dbca4e 100644
--- a/Assets/Scripts/Streamingle/DonationThrowable/ThrowableObject.cs
+++ b/Assets/Scripts/Streamingle/DonationThrowable/ThrowableObject.cs
@@ -336,6 +336,19 @@ namespace Streamingle
Deactivate();
}
+ ///
+ /// Immediately despawn this object, skipping the flight, the post-arrival
+ /// wait and the shrink-out animation. Called by the launcher's ClearAll to
+ /// reset everything at once (e.g. to clear a donation-burst backlog).
+ /// Pooled objects are deactivated; non-pooled ones are destroyed.
+ ///
+ public void ForceReset()
+ {
+ // Deactivate() already cancels invokes/coroutines and restores scale,
+ // and routes to pool-deactivate vs destroy based on the launcher.
+ Deactivate();
+ }
+
private void Deactivate()
{
CancelInvoke();
diff --git a/Assets/Scripts/Streamingle/DonationThrowable/ThrowableObjectLauncher.cs b/Assets/Scripts/Streamingle/DonationThrowable/ThrowableObjectLauncher.cs
index 33479aab7..530892b3c 100644
--- a/Assets/Scripts/Streamingle/DonationThrowable/ThrowableObjectLauncher.cs
+++ b/Assets/Scripts/Streamingle/DonationThrowable/ThrowableObjectLauncher.cs
@@ -59,6 +59,10 @@ namespace Streamingle
private GameObject[][] objectPool;
private int[] poolIndices;
+ // Objects spawned directly (when pooling is off) so ClearAll can find them.
+ private readonly System.Collections.Generic.List activeNonPooled =
+ new System.Collections.Generic.List();
+
// Auto-created collider
private SphereCollider createdTargetCollider;
private Rigidbody createdTargetRigidbody;
@@ -239,6 +243,67 @@ namespace Streamingle
ThrowObject();
}
+ ///
+ /// Immediately reset only the currently-spawned (active) objects.
+ /// Pooled instances are deactivated back into the pool (the pre-allocated
+ /// reserve is left untouched); non-pooled instances are destroyed.
+ /// Also cancels any pending ThrowMultiple delays so the backlog doesn't
+ /// re-spawn right after clearing. Use this to relieve a donation-burst
+ /// pile-up that causes frame drops. Safe to call at any time.
+ ///
+ [ContextMenu("Reset: Clear All Thrown Objects")]
+ public void ClearAll()
+ {
+ // Cancel any queued ThrowMultiple delays still waiting to fire,
+ // otherwise the pending throws would immediately repopulate the scene.
+ StopAllCoroutines();
+ ClearActiveObjects();
+ }
+
+ ///
+ /// Reset only the objects currently out in the scene, leaving any pending
+ /// ThrowMultiple delays running. Useful when you want to clear what's
+ /// visible but let already-queued throws continue.
+ ///
+ public void ClearActiveObjects()
+ {
+ int cleared = 0;
+
+ // Pooled objects: deactivate every active instance back into the pool.
+ // Inactive reserve objects are skipped, so the pool stays intact.
+ if (objectPool != null)
+ {
+ foreach (var pool in objectPool)
+ {
+ if (pool == null) continue;
+ foreach (var obj in pool)
+ {
+ if (obj == null || !obj.activeInHierarchy) continue;
+
+ var throwable = obj.GetComponent();
+ if (throwable != null) throwable.ForceReset();
+ else obj.SetActive(false);
+ cleared++;
+ }
+ }
+ }
+
+ // Non-pooled objects we instantiated directly (ForceReset destroys them).
+ for (int i = activeNonPooled.Count - 1; i >= 0; i--)
+ {
+ var obj = activeNonPooled[i];
+ if (obj == null) continue;
+
+ var throwable = obj.GetComponent();
+ if (throwable != null) throwable.ForceReset();
+ else Destroy(obj);
+ cleared++;
+ }
+ activeNonPooled.Clear();
+
+ UnityEngine.Debug.Log($"[ThrowableObjectLauncher] Cleared {cleared} active object(s)");
+ }
+
private GameObject GetObject(int prefabIndex)
{
GameObject obj;
@@ -279,6 +344,8 @@ namespace Streamingle
throwable = obj.AddComponent();
}
throwable.launcher = this;
+ // Track so ClearAll can reset directly-instantiated objects.
+ activeNonPooled.Add(obj);
return obj;
}
}