OverdriveAssets.cs
using Sandbox;
using System.Threading.Tasks;
namespace PaintballBaddies;

// Workshop dependencies are restored through Cloud, never through a machine-specific cache path.
public static class OverdriveAssets
{
    public const string RobotPath="models/sausage/grumpy/grumpy.vmdl";
    public const string HeftyPath="models/sausage/grumpy/grumpy_hefty.vmdl";
    public const string NativeTerryPath="models/citizen/citizen.vmdl";
    public const string ShotgunPath="models/weapons/sbox_shotgun_spaghellim4/w_spaghellim4.vmdl";
    public const string PlatePath="models/props/kitchen_utensils/kitchen_utensils_b_dish.vmdl";
    public const string KnifePath="models/props/trim_sheets/kitchen/chef_knife.vmdl";
    public const string CrossbowPath="weapons/rust_crossbow/rust_crossbow.vmdl";
    public const string BoltPath="weapons/rust_crossbow/rust_crossbow_bolt.vmdl";
    public const string ShellPath="models/weapons/sbox_ammo/12g_shell/12g_shell_casing.vmdl";
    public const string EggPath="models/dev/sphere.vmdl";
    public const string RealEggPath="models/kitchen/egg.vmdl";
    public const string EggCartonPath="models/kitchen/egg_carton.vmdl";
    public const string EggShellHalfPath="models/kitchen/egg_shell_half.vmdl";
    // Dual 1911 pistols (Facepunch, CC0) and a pistol report; optional: if
    // they fail to download the game falls back to the shotgun.
    public static Model PistolModel {get;private set;}
    public static SoundEvent PistolSound {get;private set;}
    public static Model GrenadeModel {get;private set;}
    private static Task loading,pistols,grenade;
    public static Task LoadGrenade()=>grenade ??= DownloadGrenade();
    private static async Task DownloadGrenade()
    {
        try{GrenadeModel=await Cloud.Load<Model>("facepunch.w_he_grenade");}
        catch(System.Exception e){Log.Warning($"GRENADE_ASSET {e.Message}");}
    }
    // Loaded on its own so a hotload or a failed download never blocks the game.
    public static Task LoadPistols()=>pistols ??= DownloadPistols();
    private static async Task DownloadPistols()
    {
        try{PistolModel=await Cloud.Load<Model>("facepunch.w_1911");PistolSound=await Cloud.Load<SoundEvent>("vidya.pistol-shoot");}
        catch(System.Exception e){Log.Warning($"DUAL_PISTOLS {e.Message}");}
        Log.Info($"DUAL_PISTOLS model={(PistolModel is {IsError:false} ? PistolModel.Name : "missing")} bounds={PistolModel?.Bounds} sound={PistolSound?.ResourcePath}");
    }
    public static bool Ready {get;private set;}
    public static string Error {get;private set;}="";
    public static Task Load()=>loading ??= Download();
    private static async Task Download()
    {
        try
        {
            // Warm the optional effect material before the first freeze lands.
            _=CryoBurst.Load();
            await Cloud.Load<Model>("facepunch.w_spaghellim4");
            await Cloud.Load<Model>("facepunch.12gshellcasing");
            await Cloud.Load<Model>("facepunch.kitchen_utensils_b_dish");
            await Cloud.Load<Model>("facepunch.chef_knife");
            await Cloud.Load<SoundEvent>("vidya.shotgun-shoot");
            await Cloud.Load<Model>("rust.rust_crossbow");
            await Cloud.Load<Model>("rust.rust_crossbow_bolt");
            _=LoadPistols();_=LoadGrenade();
            Ready=!Model.Load(RobotPath).IsError && !Model.Load(ShotgunPath).IsError && !Model.Load(PlatePath).IsError && !Model.Load(KnifePath).IsError;
            Ready=Ready && !Model.Load(HeftyPath).IsError && !Model.Load(CrossbowPath).IsError && !Model.Load(BoltPath).IsError && !Model.Load(EggPath).IsError;
            if(!Ready)Error="Enemy or weapon download failed. Restart to retry.";
        }
        catch(System.Exception e){Error="Prototype assets could not download. Restart to retry.";Log.Warning($"OVERDRIVE_ASSETS {e.Message}");}
    }
}