// Crest Water System // Copyright © 2024 Wave Harmonic. All rights reserved. using UnityEditor; using UnityEngine; using WaveHarmonic.Crest.Editor; namespace WaveHarmonic.Crest.ShallowWater.Editor { static class Validators { static readonly string s_TransformName = $"{nameof(Transform)}"; static readonly string s_DepthProbeName = $"{nameof(DepthProbe)}"; static readonly string s_ShallowWaterSimulationName = $"{nameof(ShallowWaterSimulation)}"; static void FixSetFeatureEnabled(SerializedObject so, string paramName, bool enabled) { var property = so.FindProperty(paramName); var oldValue = property.boolValue; property.boolValue = enabled; DecoratedDrawer.OnChange(property, oldValue); } [Validator(typeof(ShallowWaterSimulation))] static bool Validate(ShallowWaterSimulation target, ValidatedHelper.ShowMessage messenger) { var isValid = true; var water = Crest.Editor.Validators.Water; if (target._InjectShape == ShallowWaterSimulationInjection.Level) { isValid &= Crest.Editor.Validators.ValidateLod ( OptionalLod.Get(typeof(LevelLod)), messenger, water ); } else if (target._InjectShape == ShallowWaterSimulationInjection.Waves) { isValid &= Crest.Editor.Validators.ValidateLod ( OptionalLod.Get(typeof(AnimatedWavesLod)), messenger, water ); } if (target._InjectFlow) { isValid &= Crest.Editor.Validators.ValidateLod ( OptionalLod.Get(typeof(FlowLod)), messenger, water ); } if (target._InjectFoam) { isValid &= Crest.Editor.Validators.ValidateLod ( OptionalLod.Get(typeof(FoamLod)), messenger, water ); } if (!target._SampleDepthProbeDirectly && target._Mode != ShallowWaterSimulationMode.Baked) { isValid &= Crest.Editor.Validators.ValidateLod ( OptionalLod.Get(typeof(DepthLod)), messenger, water ); } if (target._SampleDepthProbeDirectly && target._Mode != ShallowWaterSimulationMode.Baked) { if (target._DepthProbe == null) { messenger ( $"There is no {s_DepthProbeName} present on this {nameof(GameObject)}. " + $"A {s_DepthProbeName} is often needed other than for simple cases like pools.", $"Add a {s_DepthProbeName}.", ValidatedHelper.MessageType.Info, target, (x, _) => { var probe = ValidatedHelper.FixAttachComponent(x); probe.Managed = true; probe.Scale = new(target._Width, target._Width); probe.OverridePosition = target.Movable; } ); } } if (target.Placement != Placement.Fixed && target.SampleDepthProbeDirectly && target._DepthProbe != null && target._DepthProbe.Type == DepthProbeMode.Baked) { messenger ( $"The attached {nameof(DepthProbe)} is baked, but {nameof(ShallowWaterSimulation.Placement)} is not set to {nameof(Placement.Fixed)}. " + $"{nameof(DepthProbe)} cannot be baked at runtime, so these are incompatible.", $"Either set the {nameof(DepthProbe)} to {nameof(DepthProbeMode.RealTime)} or set the {nameof(ShallowWaterSimulation)} to {nameof(Placement.Fixed)}.", ValidatedHelper.MessageType.Error, target ); } if (target._Debug != null) { var isDebugging = target._Debug._SkipUpdate || target._Debug._SkipAdvect || target._Debug._SkipAdvectHeights || target._Debug._SkipUpdateHeight || target._Debug._SkipUpdateVelocities; if (isDebugging) { messenger ( "Debug options currently disable one or more stages of the simulation.", "Enable all simulation stages.", ValidatedHelper.MessageType.Warning, target, (so, _) => { FixSetFeatureEnabled(so, $"{nameof(ShallowWaterSimulation._Debug)}.{nameof(ShallowWaterSimulation._Debug._SkipUpdate)}", false); FixSetFeatureEnabled(so, $"{nameof(ShallowWaterSimulation._Debug)}.{nameof(ShallowWaterSimulation._Debug._SkipUpdateHeight)}", false); FixSetFeatureEnabled(so, $"{nameof(ShallowWaterSimulation._Debug)}.{nameof(ShallowWaterSimulation._Debug._SkipAdvect)}", false); FixSetFeatureEnabled(so, $"{nameof(ShallowWaterSimulation._Debug)}.{nameof(ShallowWaterSimulation._Debug._SkipAdvectHeights)}", false); FixSetFeatureEnabled(so, $"{nameof(ShallowWaterSimulation._Debug)}.{nameof(ShallowWaterSimulation._Debug._SkipUpdateVelocities)}", false); } ); } if (target._Debug._ShowSimulationData) { messenger ( "Debug drawing of simulation data currently active.", "Disable debug drawing when debugging is done to hide the overlay.", ValidatedHelper.MessageType.Info, target, (_, property) => property.boolValue = false, $"{nameof(ShallowWaterSimulation._Debug)}.{nameof(ShallowWaterSimulation._Debug._ShowSimulationData)}" ); } } if (!target._SampleDepthProbeDirectly && target.Placement == Placement.Transform && target.TryGetComponent(out var probe) && probe.isActiveAndEnabled) { messenger ( $"There is an active {nameof(DepthProbe)} on this game object, with both {nameof(ShallowWaterSimulation.SampleDepthProbeDirectly)} disabled and {nameof(ShallowWaterSimulation.Placement)} set to {Placement.Transform}. " + "This will break the movement procedure.", $"Either disable/remove the {nameof(DepthProbe)} or change one of those settings.", ValidatedHelper.MessageType.Error, target ); } if (water == null) { return isValid; } var layers = water.AnimatedWavesLod._CollisionLayers; var flag = CollisionLayers.DynamicWaves; if (target._Mode == ShallowWaterSimulationMode.RealTime && water.DynamicWavesLod.Enabled && !layers.HasFlag(flag)) { messenger ( $"It is recommended to enable the {flag} collision layer, " + "as this will solve a feedback loop where the water level grows perpetually.", $"Enable {flag} collision layer", ValidatedHelper.MessageType.Info, water, (_, y) => y.intValue = (int)(layers | flag), $"{nameof(WaterRenderer._AnimatedWavesLod)}.{nameof(WaterRenderer._AnimatedWavesLod._CollisionLayers)}" ); } return isValid; } } }