From 07acfa5801b76e1647e9d18691da3b5dd99dcc1e Mon Sep 17 00:00:00 2001 From: empty Date: Fri, 2 Jan 2026 02:46:23 +0800 Subject: [PATCH] fix: prevent ParticleSystem "duration while playing" warnings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Stop ParticleSystem immediately after AddComponent to prevent auto-play - Set playOnAwake=false on all procedural particle systems - Also add missing EventType definitions for Phase 23/24 features 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- backend/app/schemas.py | 11 +++ unity-client/Assets/Scripts/Models.cs | 46 ++++++++++ unity-client/Assets/Scripts/NetworkManager.cs | 20 +++++ .../Assets/Scripts/Visual/VFXManager.cs | 88 ++++++++++++++++++- 4 files changed, 163 insertions(+), 2 deletions(-) diff --git a/backend/app/schemas.py b/backend/app/schemas.py index 68a462a..b4b8a21 100644 --- a/backend/app/schemas.py +++ b/backend/app/schemas.py @@ -55,6 +55,17 @@ class EventType(str, Enum): # Random Events (Phase 17-C) RANDOM_EVENT = "random_event" # Random event occurred + # Economy (Phase 23) + GIVE_ITEM = "give_item" # Agent gives item to another + + # Group Activities (Phase 24) + # Group Activities (Phase 24) + GROUP_ACTIVITY = "group_activity" # Storytelling, dancing, etc. + + # VFX & Gifts (Phase 8) + VFX_EVENT = "vfx_event" # Visual effect trigger + GIFT_EFFECT = "gift_effect" # Twitch bits/sub effect + class GameEvent(BaseModel): """ diff --git a/unity-client/Assets/Scripts/Models.cs b/unity-client/Assets/Scripts/Models.cs index 45b8e93..737b311 100644 --- a/unity-client/Assets/Scripts/Models.cs +++ b/unity-client/Assets/Scripts/Models.cs @@ -353,6 +353,15 @@ namespace TheIsland.Models // Random Events (Phase 17-C) public const string RANDOM_EVENT = "random_event"; + + // Economy (Phase 23) + public const string GIVE_ITEM = "give_item"; + + // Group Activities (Phase 24) + public const string GROUP_ACTIVITY = "group_activity"; + + // Phase 8: VFX + public const string VFX_EVENT = "vfx_event"; } /// @@ -403,4 +412,41 @@ namespace TheIsland.Models public string message; public string agent_name; // Optional: affected agent } + + /// + /// Give item event data (Phase 23). + /// + [Serializable] + public class GiveItemEventData + { + public int from_id; + public int to_id; + public string item_type; // "herb", "food", "medicine" + public string message; + } + + /// + /// Group Activity event data (Phase 24). + /// + [Serializable] + public class GroupActivityEventData + { + public string activity_type; // "storytelling" + public int storyteller_id; + public string storyteller_name; + public List listener_ids; + public string content; // The story text + public string topic; + } + + /// + /// VFX event data (Phase 8). + /// + [Serializable] + public class VFXEventData + { + public string effect; // "gold_rain", "heart", "food" + public int target_id; // Optional: if -1 or 0, might mean global or specific position logic + public string message; + } } diff --git a/unity-client/Assets/Scripts/NetworkManager.cs b/unity-client/Assets/Scripts/NetworkManager.cs index 9c6f9e1..b7c38a3 100644 --- a/unity-client/Assets/Scripts/NetworkManager.cs +++ b/unity-client/Assets/Scripts/NetworkManager.cs @@ -72,6 +72,9 @@ namespace TheIsland.Network public event Action OnCraft; // Phase 16: Crafting public event Action OnUseItem; // Phase 16: Using items public event Action OnRandomEvent; // Phase 17-C: Random Events + public event Action OnGiveItem; // Phase 23: Item Exchange + public event Action OnGroupActivity; // Phase 24: Group Activities + public event Action OnVFXEvent; // Phase 8: VFX #endregion #region Private Fields @@ -377,6 +380,23 @@ namespace TheIsland.Network var randomEventData = JsonUtility.FromJson(dataJson); OnRandomEvent?.Invoke(randomEventData); Debug.Log($"[Random Event] {randomEventData.event_type}: {randomEventData.message}"); + OnRandomEvent?.Invoke(randomEventData); + Debug.Log($"[Random Event] {randomEventData.event_type}: {randomEventData.message}"); + break; + + case EventTypes.GIVE_ITEM: + var giveData = JsonUtility.FromJson(dataJson); + OnGiveItem?.Invoke(giveData); + break; + + case EventTypes.GROUP_ACTIVITY: + var groupData = JsonUtility.FromJson(dataJson); + OnGroupActivity?.Invoke(groupData); + break; + + case EventTypes.VFX_EVENT: + var vfxData = JsonUtility.FromJson(dataJson); + OnVFXEvent?.Invoke(vfxData); break; default: diff --git a/unity-client/Assets/Scripts/Visual/VFXManager.cs b/unity-client/Assets/Scripts/Visual/VFXManager.cs index 86abb7e..088d537 100644 --- a/unity-client/Assets/Scripts/Visual/VFXManager.cs +++ b/unity-client/Assets/Scripts/Visual/VFXManager.cs @@ -44,6 +44,11 @@ namespace TheIsland.Visual [SerializeField] private int dustParticleCount = 8; [SerializeField] private float dustDuration = 0.5f; + [Header("Food Poof Settings")] + [SerializeField] private Color foodColor = new Color(1f, 1f, 1f, 0.7f); // White smoke + [SerializeField] private int foodParticleCount = 15; + [SerializeField] private float foodDuration = 1.0f; + [Header("General Settings")] [SerializeField] private float effectScale = 1f; #endregion @@ -96,6 +101,17 @@ namespace TheIsland.Visual Destroy(ps.gameObject, dustDuration + 0.2f); } + /// + /// Play food poof effect (white smoke). + /// Used for feeding. + /// + public void PlayFoodPoof(Vector3 position) + { + var ps = CreateFoodPoofSystem(position); + ps.Play(); + Destroy(ps.gameObject, foodDuration + 0.5f); + } + /// /// Play an effect by type name. /// @@ -114,6 +130,10 @@ namespace TheIsland.Visual case "subscription": PlayHeartExplosion(position); break; + case "food": + case "feed": + PlayFoodPoof(position); + break; default: // Default to gold rain PlayGoldRain(position); @@ -130,9 +150,12 @@ namespace TheIsland.Visual { GameObject go = new GameObject("GoldRain_VFX"); go.transform.position = position + Vector3.up * 3f; // Start above - + ParticleSystem ps = go.AddComponent(); + // Stop immediately to prevent "duration while playing" warning + ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); var main = ps.main; + main.playOnAwake = false; main.loop = false; main.duration = goldDuration; main.startLifetime = 1.5f; @@ -203,9 +226,12 @@ namespace TheIsland.Visual { GameObject go = new GameObject("HeartExplosion_VFX"); go.transform.position = position + Vector3.up * 1.5f; - + ParticleSystem ps = go.AddComponent(); + // Stop immediately to prevent "duration while playing" warning + ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); var main = ps.main; + main.playOnAwake = false; main.loop = false; main.duration = heartDuration; main.startLifetime = 1.2f; @@ -280,7 +306,10 @@ namespace TheIsland.Visual go.transform.position = position; ParticleSystem ps = go.AddComponent(); + // Stop immediately to prevent "duration while playing" warning + ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); var main = ps.main; + main.playOnAwake = false; main.loop = false; main.duration = dustDuration; main.startLifetime = 0.4f; @@ -336,6 +365,61 @@ namespace TheIsland.Visual return ps; } + private ParticleSystem CreateFoodPoofSystem(Vector3 position) + { + GameObject go = new GameObject("FoodPoof_VFX"); + go.transform.position = position + Vector3.up * 1.5f; + + ParticleSystem ps = go.AddComponent(); + // Stop immediately to prevent "duration while playing" warning + ps.Stop(true, ParticleSystemStopBehavior.StopEmittingAndClear); + var main = ps.main; + main.playOnAwake = false; + main.loop = false; + main.duration = foodDuration; + main.startLifetime = 0.8f; + main.startSpeed = new ParticleSystem.MinMaxCurve(0.5f, 2f); + main.startSize = new ParticleSystem.MinMaxCurve(0.3f * effectScale, 0.6f * effectScale); + main.startColor = foodColor; + main.gravityModifier = -0.05f; // Slight float + main.maxParticles = foodParticleCount; + main.simulationSpace = ParticleSystemSimulationSpace.World; + + var emission = ps.emission; + emission.enabled = true; + emission.rateOverTime = 0; + // Burst + emission.SetBursts(new ParticleSystem.Burst[] { new ParticleSystem.Burst(0f, (short)foodParticleCount) }); + + var shape = ps.shape; + shape.enabled = true; + shape.shapeType = ParticleSystemShapeType.Sphere; + shape.radius = 0.4f * effectScale; + + var sizeOverLifetime = ps.sizeOverLifetime; + sizeOverLifetime.enabled = true; + AnimationCurve sizeCurve = new AnimationCurve(); + sizeCurve.AddKey(0f, 0.2f); + sizeCurve.AddKey(0.5f, 1f); + sizeCurve.AddKey(1f, 0f); + sizeOverLifetime.size = new ParticleSystem.MinMaxCurve(1f, sizeCurve); + + var colorOverLifetime = ps.colorOverLifetime; + colorOverLifetime.enabled = true; + Gradient gradient = new Gradient(); + gradient.SetKeys( + new GradientColorKey[] { new GradientColorKey(foodColor, 0f), new GradientColorKey(foodColor, 1f) }, + new GradientAlphaKey[] { new GradientAlphaKey(0.8f, 0f), new GradientAlphaKey(1f, 0.2f), new GradientAlphaKey(0f, 1f) } + ); + colorOverLifetime.color = gradient; + + var renderer = go.GetComponent(); + renderer.renderMode = ParticleSystemRenderMode.Billboard; + renderer.material = CreateParticleMaterial(foodColor); + + return ps; + } + /// /// Create a simple additive particle material. ///