diff --git a/Assets/_Project/Scripts/Client/Presentation/AmbientMotionSystem.cs b/Assets/_Project/Scripts/Client/Presentation/AmbientMotionSystem.cs index 5241975a0..fb8d43050 100644 --- a/Assets/_Project/Scripts/Client/Presentation/AmbientMotionSystem.cs +++ b/Assets/_Project/Scripts/Client/Presentation/AmbientMotionSystem.cs @@ -24,8 +24,12 @@ namespace ProjectM.Client [UpdateInGroup(typeof(PresentationSystemGroup))] public partial class AmbientMotionSystem : SystemBase { + // 2026-08-08: seabed terms FIRST. The old list was pure LAND flora (bush/grass/flower/fern/cactus) + // from the deleted meadow + arid biomes, so it matched NOTHING in the shipping seabed arena and the + // whole walk-through rustle layer was dead. The land terms are kept only so an old scene still works. static readonly System.Text.RegularExpressions.Regex FloraName = new System.Text.RegularExpressions.Regex( - "bush|grass|flower|fern|groundcover|ground_cover|wildflower|clover|reed|succulent|cactus", + "floraclump|flora_|kelp|frond|seagrass|seaweed|coral|anemone" + + "|bush|grass|flower|fern|groundcover|ground_cover|wildflower|clover|reed|succulent|cactus", System.Text.RegularExpressions.RegexOptions.IgnoreCase); struct Flora @@ -79,14 +83,22 @@ namespace ProjectM.Client { RestoreFlora(); _flora.Clear(); + // 2026-08-08: scan EVERY root. The old gate required a root literally named "BaseBiome" or + // "ExpeditionBiome*" — both went with the expedition, so this loop matched nothing and the rustle + // layer silently did nothing in the shipping arena. The seabed flora live under + // Env_SeabedKit/Seabed_Flora/FloraClump_N. foreach (var root in scene.GetRootGameObjects()) { - if (root.name != "BaseBiome" && !root.name.StartsWith("ExpeditionBiome")) continue; foreach (var t in root.GetComponentsInChildren(false)) { if (!FloraName.IsMatch(t.gameObject.name)) continue; if (t.gameObject.name.Contains("LOD")) continue; // prop roots only; LOD children follow - if (t.GetComponent() == null && t.GetComponent() == null) continue; + // The sway unit is the CLUMP ROOT, which carries no renderer of its own — only children. + // The old renderer-on-self test rejected exactly the object we want to rotate, so accept a + // renderer anywhere beneath. Skip anything whose PARENT already matched, so we tilt the + // clump once instead of tilting every stalk out of its socket. + if (t.parent != null && FloraName.IsMatch(t.parent.gameObject.name)) continue; + if (t.GetComponent() == null && t.GetComponentInChildren() == null) continue; // 1.5b: ground-flush carpet props (Flowers_Flat, Grass_*_Plane) must NEVER root-tilt — // any rotation lifts their edges off the ground; they stay fully static (shader wind only). if (t.gameObject.name.IndexOf("Flat", System.StringComparison.OrdinalIgnoreCase) >= 0