using System; using System.Collections.Generic; using UltimateWater.Utils; using UnityEngine; using UnityEngine.Rendering; namespace UltimateWater { [ExecuteInEditMode] public abstract class WaterVolumeBase : MonoBehaviour { [SerializeField] private Water _Water; [SerializeField] private WaterVolumeRenderMode _RenderMode = WaterVolumeRenderMode.Basic; [SerializeField] private bool _AffectPhysics = true; private Collider[] _Colliders; private static readonly Dictionary _ColliderToVolumeCache = new Dictionary(); [SerializeField] [InspectorWarning("Validation", InspectorWarningAttribute.InfoType.Warning)] private string _Validation; public Water Water { get { return _Water; } } public bool EnablePhysics { get { return _AffectPhysics; } } public WaterVolumeRenderMode RenderMode { get { return _RenderMode; } } public MeshRenderer[] VolumeRenderers { get; private set; } public MeshFilter[] VolumeFilters { get; private set; } protected virtual CullMode _CullMode { get { return CullMode.Back; } } public void AssignTo(Water water) { if (!(_Water == water) && !(water == null)) { DisposeRenderers(); Unregister(water); _Water = water; Register(water); if (_RenderMode != WaterVolumeRenderMode.None && Application.isPlaying) { CreateRenderers(); } } } public void EnableRenderers(bool forBorderRendering) { if (VolumeRenderers != null) { bool flag = !forBorderRendering && _Water.enabled; for (int i = 0; i < VolumeRenderers.Length; i++) { VolumeRenderers[i].enabled = flag; } } } public void DisableRenderers() { if (VolumeRenderers != null) { for (int i = 0; i < VolumeRenderers.Length; i++) { VolumeRenderers[i].enabled = false; } } } public bool IsPointInside(Vector3 point) { for (int i = 0; i < _Colliders.Length; i++) { if (_Colliders[i].IsPointInside(point)) { return true; } } return false; } public static WaterVolumeBase GetWaterVolume(Collider collider) where T : WaterVolumeBase { return GetWaterVolume(collider) as T; } public static WaterVolumeBase GetWaterVolume(Collider collider) { WaterVolumeBase value; if (!_ColliderToVolumeCache.TryGetValue(collider, out value)) { value = collider.GetComponent(); if (!(value != null)) { value = (_ColliderToVolumeCache[collider] = null); } else { _ColliderToVolumeCache[collider] = value; } } return value; } protected void OnEnable() { _Colliders = GetComponents(); base.gameObject.layer = WaterProjectSettings.Instance.WaterCollidersLayer; Register(_Water); if (_RenderMode != WaterVolumeRenderMode.None && _Water != null && Application.isPlaying) { CreateRenderers(); } } protected void OnDisable() { DisposeRenderers(); Unregister(_Water); } private void Update() { if (VolumeRenderers != null) { for (int i = 0; i < VolumeRenderers.Length; i++) { VolumeRenderers[i].SetPropertyBlock(_Water.Renderer.PropertyBlock); } } } protected void OnValidate() { _Colliders = GetComponents(); for (int i = 0; i < _Colliders.Length; i++) { if (!_Colliders[i].isTrigger) { _Colliders[i].isTrigger = true; } } if (_Water == null) { _Water = GetComponentInChildren(); } } protected void Reset() { if (_Water == null) { _Water = Utilities.GetWaterReference(); } } protected abstract void Register(Water water); protected abstract void Unregister(Water water); internal void SetLayer(int layer) { if (VolumeRenderers != null) { for (int i = 0; i < VolumeRenderers.Length; i++) { VolumeRenderers[i].gameObject.layer = layer; } } } private void DisposeRenderers() { if (VolumeRenderers == null) { return; } for (int i = 0; i < VolumeRenderers.Length; i++) { if (VolumeRenderers[i] != null) { UnityEngine.Object.Destroy(VolumeRenderers[i].gameObject); } } VolumeRenderers = null; VolumeFilters = null; } protected virtual void CreateRenderers() { int num = _Colliders.Length; VolumeRenderers = new MeshRenderer[num]; VolumeFilters = new MeshFilter[num]; Material sharedMaterial = ((_CullMode != CullMode.Back) ? _Water.Materials.VolumeBackMaterial : _Water.Materials.VolumeMaterial); for (int i = 0; i < num; i++) { Collider collider = _Colliders[i]; BoxCollider boxCollider; GameObject obj; SphereCollider sphereCollider; MeshCollider meshCollider; if ((boxCollider = collider as BoxCollider) != null) { HandleBoxCollider(out obj, boxCollider); } else if ((sphereCollider = collider as SphereCollider) != null) { HandleSphereCollider(out obj, sphereCollider); } else if ((meshCollider = collider as MeshCollider) != null) { HandleMeshCollider(out obj, meshCollider); } else { CapsuleCollider capsuleCollider; if (!((capsuleCollider = collider as CapsuleCollider) != null)) { throw new InvalidOperationException("Unsupported collider type."); } HandleCapsuleCollider(out obj, capsuleCollider); } obj.hideFlags = HideFlags.DontSave; obj.name = "Volume Renderer"; obj.layer = WaterProjectSettings.Instance.WaterLayer; obj.transform.SetParent(base.transform, false); UnityEngine.Object.Destroy(obj.GetComponent()); MeshRenderer component = obj.GetComponent(); component.sharedMaterial = sharedMaterial; component.shadowCastingMode = ShadowCastingMode.Off; component.receiveShadows = false; component.lightProbeUsage = LightProbeUsage.Off; component.enabled = true; component.SetPropertyBlock(_Water.Renderer.PropertyBlock); VolumeRenderers[i] = component; VolumeFilters[i] = component.GetComponent(); } } private static void HandleBoxCollider(out GameObject obj, BoxCollider boxCollider) { obj = GameObject.CreatePrimitive(PrimitiveType.Cube); obj.transform.localScale = boxCollider.size; obj.transform.localPosition = boxCollider.center; } private void HandleMeshCollider(out GameObject obj, MeshCollider meshCollider) { Mesh sharedMesh = meshCollider.sharedMesh; if (sharedMesh == null) { throw new InvalidOperationException("MeshCollider used to mask water doesn't have a mesh assigned."); } obj = new GameObject { hideFlags = HideFlags.DontSave }; MeshFilter meshFilter = obj.AddComponent(); meshFilter.sharedMesh = sharedMesh; obj.AddComponent(); } private static void HandleSphereCollider(out GameObject obj, SphereCollider sphereCollider) { float num = sphereCollider.radius * 2f; obj = GameObject.CreatePrimitive(PrimitiveType.Sphere); obj.transform.localScale = new Vector3(num, num, num); obj.transform.localPosition = sphereCollider.center; } private static void HandleCapsuleCollider(out GameObject obj, CapsuleCollider capsuleCollider) { float num = capsuleCollider.height * 0.5f; float num2 = capsuleCollider.radius * 2f; obj = GameObject.CreatePrimitive(PrimitiveType.Capsule); obj.transform.localPosition = capsuleCollider.center; switch (capsuleCollider.direction) { case 0: obj.transform.localEulerAngles = new Vector3(0f, 0f, 90f); obj.transform.localScale = new Vector3(num, num2, num2); break; case 1: obj.transform.localScale = new Vector3(num2, num, num2); break; case 2: obj.transform.localEulerAngles = new Vector3(90f, 0f, 0f); obj.transform.localScale = new Vector3(num2, num2, num); break; } } protected string Validation() { string text = string.Empty; if (_Water == null) { text += "warning: assign Water reference"; } return text; } } }