Grid/Destruction/WallColumnDamage.cs
using Sandbox;
using Sandbox.Sboku;
using SWB.Base;
using System;
using System.Numerics;

public sealed class WallColumnDamage : Component
{
    //public GameObject SnowCap { get; set; }

    [Property] public int GridIndex { get; set; }
    [Property] public int MaxHealth { get; set; } = 62;
    [Property] public DebrisVisualPool DebrisPool { get; set; }
    [Property] public GameObject DustPrefab { get; set; }
    [Property] public Material WallMaterial { get; set; }
    [Property] public int ColumnHeight { get; set; }

    [Property] public float GridSize { get; set; }
    [Property] public bool IsIndestructible { get; set; }
    Model BoxModel;
    private int health;
    private bool destroyed;
    private bool isSegmented;
    public int DestroyedSegmentCount { get; private set; }
    public bool FullyDestroyed { get; private set; }
    protected override void OnStart()
    {
        health = MaxHealth;
        BoxModel = Model.Load("models/dev/box.vmdl");
    }

    public void OnSegmentDestroyed(Vector3 hitWorldPos)
    {
        if (FullyDestroyed)
            return;

        DestroyedSegmentCount++;

        // =========================
        //  YLIN SEGMENTTI → POISTA LUMI + PIENI DUST
        // =========================
        /*float columnWorldHeight = GridSize * ColumnHeight;
        float columnBottomZ = Transform.Position.z - columnWorldHeight * 0.5f;
        float topSegmentMinZ = columnBottomZ + (ColumnHeight - 1) * GridSize;

        if (hitWorldPos.z >= topSegmentMinZ)
        {
            if (SnowCap.IsValid())
            {
                SnowCap.Destroy();
                SnowCap = null;
            }
        }*/

        // 💨 PIENI SAVUPUFFI YLÄOSASSA
        if (DustPrefab.IsValid())
        {
            var dust = DustPrefab.Clone(
                new Vector3(
                    Transform.Position.x,
                    Transform.Position.y,
                    hitWorldPos.z
                )
            );
            dust.DestroyAsync(1.5f);
        }

        // =========================
        //  KOKO PYLVÄS TUHOUTUU
        // =========================
        if (DestroyedSegmentCount >= 2)
        {
            FullyDestroyed = true;
            DestroyWholeColumn(hitWorldPos);
            RpcDestroyWholeColumn(hitWorldPos);
        }
    }



    // =========================
    // CLIENT → HOST
    // =========================
    [Rpc.Host]
    public void RpcHit(int damage, Vector3 hitWorldPos)
    {
        if (destroyed || IsIndestructible)
            return;

        if (!isSegmented)
        {
            ConvertToSegmented();
            RpcConvertToSegmented();
        }
        
        ApplyDamage(damage, hitWorldPos);
    }

    [Rpc.Broadcast]
    private void RpcConvertToSegmented()
    {
        if (isSegmented)
            return;

        ConvertToSegmented();
    }
    
    private void ConvertToSegmented()
    {
        isSegmented = true;

        var worldRot = Transform.Rotation;
        var worldScale = Transform.Scale;

        float columnWorldHeight = GridSize * ColumnHeight;

        // 🔑 PYLVAAN ALAPINTA
        Vector3 columnBottom =
            Transform.Position - Vector3.Up * (columnWorldHeight * 0.5f);

        // Poista vanha pylväs
        Components.Get<ModelRenderer>()?.Destroy();
        Components.Get<BoxCollider>()?.Destroy();
        Components.Get<ModelPhysics>()?.Destroy();

        // 🔑 Parent ei enää skaalaa
        Transform.Scale = Vector3.One;

        for (int i = 0; i < ColumnHeight; i++)
        {
            var seg = new GameObject($"WallSeg_{i}");
            seg.SetParent(GameObject, false);

            // 🔥 OIKEA WORLD-POSITION
            seg.Transform.Position =
                columnBottom + Vector3.Up * ((i + 0.5f) * GridSize);

            seg.Transform.Rotation = worldRot;

            // 🔑 Skaala lapselle
            seg.Transform.Scale = new Vector3(
                worldScale.x,
                worldScale.y,
                worldScale.z / ColumnHeight
            );

            var renderer = seg.Components.Create<ModelRenderer>();
            renderer.Model = BoxModel;

            var wallMaterial = WallMaterial.CreateCopy();

            // 🔑 segmentin z-skaala määrittää tekstuurin pystytoiston,
            //    jotta UV ei veny/puristu kun pylväs pilkotaan osiin
            float segmentScaleZ = worldScale.z / ColumnHeight;
            wallMaterial.Set(
                "g_vTexCoordScale",
                new Vector2(1f, segmentScaleZ)
            );

            // 🔑 offset jatkaa UV:tä ylöspäin segmentin koon mukaan
            wallMaterial.Set(
                "g_vTexCoordOffset",
                new Vector2(0f, i * segmentScaleZ)
            );
            renderer.MaterialOverride = wallMaterial;

            var collider = seg.Components.Create<BoxCollider>();
            collider.Static = true;

            var dmg = seg.Components.Create<WallSegmentDamage>();
           
            dmg.ParentColumn = this;
            dmg.MaxHealth = MaxHealth / ColumnHeight;
        }
    }


    


    // =========================
    // HOST LOGIC
    // =========================
    private void ApplyDamage(int damage, Vector3 hitWorldPos)
    {
        if (!Networking.IsHost)
            return;

        health -= damage;

        if (health > 0)
            return;

        destroyed = true;

        // 🔥 tee hostilla heti
        DestroyVisual(hitWorldPos);

        // 🔑 kerro kaikille muille
        RpcDestroyVisual(hitWorldPos);
    }

    // =========================
    // HOST → ALL
    // =========================
    [Rpc.Broadcast]
    private void RpcDestroyWholeColumn(Vector3 hitWorldPos)
    {
        if (Networking.IsHost)
            return;

        DestroyWholeColumn(hitWorldPos);
    }
    [Rpc.Broadcast]
    private void RpcDestroyVisual(Vector3 hitWorldPos)
    {
        if (destroyed && Networking.IsHost)
            return;

        destroyed = true;
        DestroyVisual(hitWorldPos);
    }

    // =========================
    // VISUAL
    // =========================
    private void DestroyWholeColumn(Vector3 hitWorldPos)
    {
        /*if (SnowCap.IsValid())
        {
            SnowCap.Destroy();
            SnowCap = null;
        }*/

        if (DustPrefab.IsValid())
        {
            var dust = DustPrefab.Clone(hitWorldPos + Vector3.Up * 16f);
            dust.DestroyAsync(3f);
        }

        DebrisPool.SpawnColumnDebris(
            Transform.Position,
            ColumnHeight,
            GridSize,
            0,
            WallMaterial
        );

        GameObject.Destroy();
    }

    private void DestroyVisual(Vector3 hitWorldPos)
{
    /*if (SnowCap.IsValid())
    {
        SnowCap.Destroy();
        SnowCap = null;
    }*/

    if (DustPrefab.IsValid())
    {
        var dust = DustPrefab.Clone(hitWorldPos + Vector3.Up * 16f);
        dust.DestroyAsync(1.5f);
    }

    DebrisPool.SpawnColumnDebris(
        Transform.Position,
        ColumnHeight,
        GridSize,
        0,
        WallMaterial
    );

    GameObject.Destroy();
}

}