// hideable.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

[DisallowMultipleComponent]
public class Hideable : MonoBehaviour
{
    [Range(0f, 1f)]
    public float hiddenAlpha = 0.25f;
    public bool forceMaterialInstanceFallback = false;

    Renderer[] renderers;
    MaterialPropertyBlock mpb;
    Dictionary<Renderer, Material[]> instancedMaterials = new Dictionary<Renderer, Material[]>();
    bool isHidden = false;

    void Awake()
    {
        renderers = GetComponentsInChildren<Renderer>(includeInactive: true);
        mpb = new MaterialPropertyBlock();
    }

    public void SetHidden(bool hidden)
    {
        if (isHidden == hidden) return;
        isHidden = hidden;
        if (hidden) ApplyHidden(); else RevertHidden();
    }

    void ApplyHidden()
    {
        foreach (var r in renderers)
        {
            if (r == null) continue;
            bool mpbWorked = TrySetAlphaViaMPB(r, hiddenAlpha);
            if (!mpbWorked || forceMaterialInstanceFallback)
            {
                InstanceAndSetMaterials(r, hiddenAlpha);
            }
            else
            {
                SafeSetShadows(r, false);
            }
        }
    }

    void RevertHidden()
    {
        foreach (var r in renderers)
        {
            if (r == null) continue;
            try { r.SetPropertyBlock(null); } catch { }
            if (instancedMaterials.TryGetValue(r, out var mats))
            {
                try { r.sharedMaterials = mats; } catch { }
                instancedMaterials.Remove(r);
            }
            SafeSetShadows(r, true);
        }
    }

    bool TrySetAlphaViaMPB(Renderer r, float alpha)
    {
        var mat = r.sharedMaterial;
        if (mat == null) return false;
        string colorProp = null;
        if (mat.HasProperty("_BaseColor")) colorProp = "_BaseColor";
        else if (mat.HasProperty("_Color")) colorProp = "_Color";
        if (colorProp == null) return false;
        try
        {
            Color current = mat.GetColor(colorProp);
            current.a = alpha;
            mpb.Clear();
            mpb.SetColor(colorProp, current);
            if (mat.HasProperty("_Surface")) mpb.SetFloat("_Surface", 1f);
            r.SetPropertyBlock(mpb);
            return true;
        }
        catch { return false; }
    }

    void InstanceAndSetMaterials(Renderer r, float alpha)
    {
        if (r == null) return;
        if (!instancedMaterials.ContainsKey(r))
        {
            try { instancedMaterials[r] = r.sharedMaterials; } catch { }
        }
        Material[] mats;
        try { mats = r.materials; } catch { return; }
        for (int i = 0; i < mats.Length; i++)
        {
            var m = mats[i];
            if (m == null) continue;
            if (m.HasProperty("_BaseColor"))
            {
                Color c = m.GetColor("_BaseColor");
                c.a = alpha;
                m.SetColor("_BaseColor", c);
                if (m.HasProperty("_Surface")) m.SetFloat("_Surface", 1f);
                m.renderQueue = 3000;
            }
            else if (m.HasProperty("_Color"))
            {
                Color c = m.GetColor("_Color");
                c.a = alpha;
                m.SetColor("_Color", c);
                ConfigureMaterialForTransparency(m);
            }
            else
            {
                ConfigureMaterialForTransparency(m);
            }
            mats[i] = m;
        }
        try { r.materials = mats; } catch { }
        SafeSetShadows(r, false);
    }

    static void ConfigureMaterialForTransparency(Material m)
    {
        if (m == null) return;
        try
        {
            m.SetOverrideTag("RenderType", "Transparent");
            m.SetFloat("_Mode", 3f);
            m.SetInt("_SrcBlend", (int)BlendMode.SrcAlpha);
            m.SetInt("_DstBlend", (int)BlendMode.OneMinusSrcAlpha);
            if (m.HasProperty("_ZWrite")) m.SetInt("_ZWrite", 0);
            m.DisableKeyword("_ALPHATEST_ON");
            m.EnableKeyword("_ALPHABLEND_ON");
            m.DisableKeyword("_ALPHAPREMULTIPLY_ON");
            m.renderQueue = 3000;
        }
        catch { }
    }

    static void SafeSetShadows(Renderer r, bool enable)
    {
        try
        {
            r.shadowCastingMode = enable ? ShadowCastingMode.On : ShadowCastingMode.Off;
            r.receiveShadows = enable;
        }
        catch { }
    }
}
//showbehindwalls.cs
using System.Collections.Generic;
using UnityEngine;

[DisallowMultipleComponent]
public class ShowBehindWalls : MonoBehaviour
{
    public Transform target;
    public LayerMask hideableLayerMask = ~0;
    public float maxDistance = 0f;
    public bool active = true;

    Camera cam;
    readonly HashSet<Renderer> currentHidden = new HashSet<Renderer>();
    readonly List<RaycastHit> hitBuffer = new List<RaycastHit>(32);

    void Awake()
    {
        cam = GetComponent<Camera>();
        if (cam == null) cam = Camera.main;
    }

    void Update()
    {
        if (!active || cam == null || target == null) 
        {
            RestoreAll();
            return;
        }

        Vector3 camPos = cam.transform.position;
        Vector3 dir = (target.position - camPos);
        float dist = dir.magnitude;
        if (dist <= Mathf.Epsilon) 
        {
            RestoreAll();
            return;
        }

        dir /= dist;
        float castDist = (maxDistance > 0f) ? maxDistance : dist - 0.1f;

        hitBuffer.Clear();
        RaycastHit[] hits = Physics.RaycastAll(camPos, dir, castDist, hideableLayerMask);
        if (hits != null && hits.Length > 0)
        {
            for (int i = 0; i < hits.Length; i++) hitBuffer.Add(hits[i]);
        }

        var hitRenderers = new HashSet<Renderer>();
        for (int i = 0; i < hitBuffer.Count; i++)
        {
            var hit = hitBuffer[i];
            if (hit.collider == null) continue;
            Renderer r = hit.collider.GetComponent<Renderer>() 
                         ?? hit.collider.GetComponentInParent<Renderer>() 
                         ?? hit.collider.GetComponentInChildren<Renderer>();
            if (r == null) continue;
            if (r.transform.IsChildOf(target)) continue;
            hitRenderers.Add(r);
        }

        var toRestore = new List<Renderer>();
        foreach (var r in currentHidden)
            if (!hitRenderers.Contains(r)) toRestore.Add(r);
        foreach (var r in toRestore)
        {
            var hideable = r.GetComponentInParent<Hideable>();
            if (hideable != null) hideable.SetHidden(false);
            currentHidden.Remove(r);
        }

        foreach (var r in hitRenderers)
        {
            if (currentHidden.Contains(r)) continue;
            var hideable = r.GetComponentInParent<Hideable>();
            if (hideable != null)
            {
                hideable.SetHidden(true);
                currentHidden.Add(r);
            }
        }
    }

    void RestoreAll()
    {
        foreach (var r in currentHidden)
        {
            if (r == null) continue;
            var hideable = r.GetComponentInParent<Hideable>();
            if (hideable != null) hideable.SetHidden(false);
        }
        currentHidden.Clear();
    }

    void OnDisable() => RestoreAll();
    void OnDestroy() => RestoreAll();
}