using Unity.Entities;
using UnityEngine;
namespace ProjectM.Client
{
///
/// Client-only ATMOSPHERE cross-fade for the two-region world. A managed presentation system
/// (SystemBase, main thread, NO Burst) in that OBSERVES the
/// follow-camera's world-space X and lerps fog + Trilight sky-ambient between
/// the lush cyan meadow base (origin) and the hostile orange arid expedition (+1000 X) — mirroring
/// HudSystem's region split at camera X > 500. The directional light + skybox + post-FX volume stay
/// GLOBAL; only fog colour/density + ambient sky colour shift per region. Pure presentation: never mutates
/// the simulation, no ECS query (camera + RenderSettings only). Knobs live in
/// (falls back to baked defaults when absent). Guarded to the gameplay
/// "Game" scene so it never restyles the menu. Fog enable/mode + equator/ground ambient are baked into the
/// scene; this only drives the per-region deltas. Phase 1.5b: also drives a per-room-biome tint on the
/// expedition ground quads (MaterialPropertyBlock — the material asset is never touched).
///
[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
[UpdateInGroup(typeof(PresentationSystemGroup))]
public partial class WorldAtmosphereSystem : SystemBase
{
Camera _cam;
MeshRenderer[] _ground;
MaterialPropertyBlock _mpb;
Color _groundCur;
static readonly int BaseColorId = Shader.PropertyToID("_BaseColor");
protected override void OnUpdate()
{
if (UnityEngine.SceneManagement.SceneManager.GetActiveScene().name != "Game") return;
if (_cam == null) _cam = Camera.main;
if (_cam == null) return;
var cfg = WorldAtmosphereConfig.Instance;
float boundary = cfg != null ? cfg.BoundaryX : 500f;
float half = cfg != null ? Mathf.Max(1f, cfg.BlendHalfWidth) : 80f;
Color baseFog = cfg != null ? cfg.BaseFogColor : new Color(0.09f, 0.13f, 0.14f, 1f);
float baseDen = cfg != null ? cfg.BaseFogDensity : 0.010f;
Color baseAmb = cfg != null ? cfg.BaseAmbientSky : new Color(0.32f, 0.38f, 0.48f, 1f);
Color expFog = cfg != null ? cfg.ExpeditionFogColor : new Color(0.24f, 0.13f, 0.06f, 1f);
float expDen = cfg != null ? cfg.ExpeditionFogDensity : 0.016f;
Color expAmb = cfg != null ? cfg.ExpeditionAmbientSky : new Color(0.45f, 0.31f, 0.20f, 1f);
// Step 14 (expedition redesign): the EXPEDITION-side palette keys on the replicated per-room biome
// (RunInfo.CurrentBiome) so every room re-themes — the camera-X blend still owns the base↔run fade.
// Palettes are code consts (cosmetic; per-biome config knobs can layer on later without churn).
// Phase 1.5: all palettes moved to the dark-ambient set (dynamic lights carry readability).
// Ground tints are ABSOLUTE _BaseColor values (the MPB replaces the authored arid sand tint).
Color groundTarget = new Color(0.60f, 0.56f, 0.50f, 1f); // authored arid sand (Mat_Ground_Arid_Dark)
bool haveRun = SystemAPI.TryGetSingleton(out var runInfo);
if (haveRun && runInfo.Lifecycle != ProjectM.Simulation.RunLifecycle.Staging)
{
switch (runInfo.CurrentBiome)
{
case ProjectM.Simulation.RoomBiomeId.Meadow:
expFog = new Color(0.10f, 0.16f, 0.10f, 1f); expDen = 0.012f;
expAmb = new Color(0.30f, 0.42f, 0.32f, 1f);
groundTarget = new Color(0.47f, 0.55f, 0.43f, 1f);
break;
case ProjectM.Simulation.RoomBiomeId.Cavern:
expFog = new Color(0.06f, 0.08f, 0.12f, 1f); expDen = 0.020f;
expAmb = new Color(0.24f, 0.28f, 0.38f, 1f);
groundTarget = new Color(0.42f, 0.46f, 0.55f, 1f);
break;
case ProjectM.Simulation.RoomBiomeId.Blight:
expFog = new Color(0.13f, 0.07f, 0.15f, 1f); expDen = 0.022f;
expAmb = new Color(0.32f, 0.24f, 0.38f, 1f);
groundTarget = new Color(0.52f, 0.42f, 0.58f, 1f);
break;
// Arid keeps the config/default burnt-dusk orange + sand ground above.
}
}
float x = _cam.transform.position.x;
float t = Mathf.Clamp01((x - (boundary - half)) / (2f * half));
t = t * t * (3f - 2f * t); // smoothstep
RenderSettings.fogColor = Color.Lerp(baseFog, expFog, t);
RenderSettings.fogDensity = Mathf.Lerp(baseDen, expDen, t);
RenderSettings.ambientSkyColor = Color.Lerp(baseAmb, expAmb, t);
// Per-room-biome ground tint (expedition quads only; the meadow base keeps its authored material).
if (_ground == null)
{
var found = new System.Collections.Generic.List();
foreach (var mr in Object.FindObjectsByType(FindObjectsSortMode.None))
if (mr.gameObject.name == "Ground_Arid") found.Add(mr);
if (found.Count > 0)
{
_ground = found.ToArray();
_mpb = new MaterialPropertyBlock();
_groundCur = groundTarget; // snap on first sight — no lerp from black
}
}
if (_ground != null)
{
_groundCur = Color.Lerp(_groundCur, groundTarget, 1f - Mathf.Exp(-2.5f * UnityEngine.Time.deltaTime));
_mpb.SetColor(BaseColorId, _groundCur);
for (int i = 0; i < _ground.Length; i++)
if (_ground[i] != null) _ground[i].SetPropertyBlock(_mpb);
}
}
}
}