Files
3d-bxqz/Packages/com.waveharmonic.crest.shallow-water/Editor/Scripts/Validators.cs
zhangjiajia 81ffaaeca6 'push'
2026-05-06 16:56:59 +08:00

185 lines
8.1 KiB
C#

// 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 = $"<i>{nameof(Transform)}</i>";
static readonly string s_DepthProbeName = $"<i>{nameof(DepthProbe)}</i>";
static readonly string s_ShallowWaterSimulationName = $"<i>{nameof(ShallowWaterSimulation)}</i>";
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 <i>{nameof(GameObject)}</i>. " +
$"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<DepthProbe>(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<DepthProbe>(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;
}
}
}