185 lines
8.1 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|