ArenaSurfaceMaterials.cs
using Sandbox;
using System;
using System.Collections.Generic;
namespace PaintballBaddies;
/// <summary>Local arena finish. Workshop resources are restored when the arena unloads.</summary>
public sealed class ArenaSurfaceMaterials
{
public int FloorSurfaces { get; private set; }
public int WallSurfaces { get; private set; }
public int WorkshopMaterials { get; private set; }
private readonly List<Action> restore = new();
public void Apply( Scene scene )
{
if(ArenaSelection.Current(scene)==ArenaSelection.Restaurant)return;
if ( ArenaMap.DisplayTitle( scene ) == "Marine Base" )
{
ApplyMarine();
return;
}
// Dry concrete stays rough; independent paint decals supply the wet highlights.
var floor = Material.Load("materials/industrial_arena/floor.vmat");
var wall = Material.Load("materials/industrial_arena/wall.vmat");
var brick = Material.Load( "materials/industrial_arena/brick.vmat" );
var painted = MultiplayerSession.Find(scene)?.IsOverdrive==true ? brick : Material.Load( "materials/industrial_arena/painted_brick.vmat" );
foreach ( var r in scene.GetAllComponents<ModelRenderer>() )
{
if ( r.Model is null ) continue;
var name = r.Model.Name;
if ( name is "models/foundry/surfaces/floor.vmdl" or "models/foundry/service_yard/floor.vmdl" )
{
Override( r, floor );
FloorSurfaces++;
}
else if ( name == "models/foundry/surfaces/end_wall.vmdl" )
{
Override( r, wall );
WallSurfaces++;
}
else if ( name == "models/foundry/painted_brick_wall/wall.vmdl" || name.StartsWith( "models/foundry/service_yard/", StringComparison.Ordinal ) )
{
bool changed = false;
for ( int i = 0; i < r.Materials.Count; i++ )
{
var original = r.Materials.GetOriginal( i );
var replacement = original?.Name switch
{
"materials/foundry/bricks060/bricks060.vmat" => brick,
"models/foundry/painted_brick_wall/lower_paint.vmat" => painted,
_ => null
};
if ( replacement is null ) continue;
int slot = i;
var previous = r.Materials.GetOverride( slot );
restore.Add( () => { if ( r.IsValid() ) r.Materials.SetOverride( slot, previous ); } );
r.Materials.SetOverride( slot, replacement );
changed = true;
}
if ( changed ) WallSurfaces++;
}
}
}
private void Override( ModelRenderer renderer, Material material )
{
var previous = renderer.MaterialOverride;
var tint = renderer.Tint;
restore.Add( () =>
{
if ( !renderer.IsValid() ) return;
renderer.MaterialOverride = previous;
renderer.Tint = tint;
} );
renderer.MaterialOverride = material;
renderer.Tint = Color.White;
}
private void ApplyMarine()
{
// Replace broad concrete with a matched source compiled for the same
// blendable shader. Keep vertex blends, lightmaps and trim UVs intact;
// never inspect native world-chunk Model handles.
var finish = Material.Load("materials/arena_finish/marine_concrete.vmat");
var floor = Material.Load( "materials/concrete/floor/floor_tile_blend_01.vmat" );
if ( floor.IsValid && floor.GetTexture( "g_tColorA" ) is not null )
{
CopyConcrete(floor,finish);
SetVector( floor, "g_flTintColorA", new Vector4( .51f, .55f, .55f, 0 ) );
SetVector( floor, "g_flTintColorB", new Vector4( .30f, .36f, .35f, 0 ) );
FloorSurfaces++;
WorkshopMaterials++;
}
var wall = Material.Load( "materials/concrete/wall/concrete_rough_a.vmat" );
if ( wall.IsValid && wall.GetTexture( "g_tColorA" ) is not null )
{
CopyConcrete(wall,finish);
SetVector( wall, "g_flTintColorA", new Vector4( .69f, .71f, .68f, 0 ) );
SetVector( wall, "g_flTintColorB", new Vector4( .38f, .46f, .44f, 0 ) );
WallSurfaces++;
WorkshopMaterials++;
}
// Keep the cast-panel and damaged trim atlases intact: their seams,
// bolts and chipped edges are authored into the workshop geometry.
foreach ( var path in new[] { "materials/concrete/hotspot/concrete_cast_hs_01.vmat", "materials/trimsheets/concrete/concrete_trim_damaged_blend_01.vmat" } )
{
var material = Material.Load( path );
if ( !material.IsValid || material.GetTexture( "g_tColorA" ) is null ) continue;
SetVector( material, "g_flTintColorA", new Vector4( .69f, .72f, .72f, 0 ) );
SetVector( material, "g_flTintColorB", new Vector4( .47f, .52f, .52f, 0 ) );
WallSurfaces++;
WorkshopMaterials++;
}
// Coordinate the original metal grid with the cooler concrete palette.
var grid=Material.Load("materials/generic/floor_steel_grid_dirty_a.vmat");
if(grid.IsValid && grid.GetTexture("g_tColor") is not null)
SetVector(grid,"g_vColorTint",new Vector4(.72f,.76f,.77f,1));
}
private void CopyConcrete(Material target,Material source)
{
foreach(var key in new[]{"g_tColorA","g_tColorB","g_tNormalA","g_tNormalB","g_tRmaA","g_tRmaB"})
{
var texture=source.GetTexture(key);
if(texture is not null)SetTexture(target,key,texture);
}
}
private void SetTexture( Material material, string name, Texture value )
{
var previous = material.GetTexture( name );
if ( previous is null ) return;
restore.Add( () => { if ( material.IsValid ) material.Set( name, previous ); } );
material.Set( name, value );
}
private void SetVector( Material material, string name, Vector4 value )
{
var previous = material.GetVector4( name );
restore.Add( () => { if ( material.IsValid ) material.Set( name, previous ); } );
material.Set( name, value );
}
public void Restore()
{
for ( int i = restore.Count - 1; i >= 0; i-- ) restore[i]();
restore.Clear();
}
}