SandbagBunker.cs
using Sandbox;
namespace PaintballBaddies;

/// <summary>Reusable staggered library-bag cover; opt-in until placement review.</summary>
public sealed class SandbagBunker : Component
{
    [Property] public Vector3 Position { get; set; } = new(-850,-400,0);
    private GameObject stack;
    protected override async void OnStart()
    {
        var model=FoundryLibraryAssets.Sandbag;
        if(model.IsError)model=await Cloud.Load<Model>("facepunch.sandbag");
        if(!GameObject.IsValid() || !model.IsValid() || model.IsError)return;
        stack=new GameObject { NetworkMode=NetworkMode.Never, Name="Canvas sandbag cover" };
        stack.WorldPosition=Position;
        for(int course=0;course<13;course++)
        for(int depth=0;depth<2;depth++)
        for(int bag=0;bag<3;bag++)
        {
            var piece=new GameObject(stack) { Name="Sandbag" };
            var variation=System.MathF.Sin(course*2.3f+bag*4.1f+depth)*.65f;
            piece.LocalPosition=new Vector3((depth-.5f)*10.3f+variation,(bag-1)*20.6f+(course%2==0 ? -2.5f : 2.5f),course*3.05f);
            piece.LocalRotation=Rotation.FromYaw(((course+bag+depth)%2==0 ? 0 : 180)+variation*3);
            piece.Components.Create<ModelRenderer>().Model=model;
        }
        var collider=stack.Components.Create<BoxCollider>();
        collider.Scale=new Vector3(21,65,40.8f);collider.Center=new Vector3(0,0,20.4f);collider.Static=true;
        var cover=stack.Components.Create<CoverSurface>();cover.ModelHeight=40.8f;
        Log.Info($"SANDBAG_BUNKER ready=True bags=78 height=40.8 position={Position}");
    }
    protected override void OnDestroy() { if(stack.IsValid())stack.Destroy(); }
}