Primitives.cs
namespace NiuLai;

public static class Primitives
{
	public const string Box = "models/dev/box.vmdl";
	public const string Plane = "models/dev/plane.vmdl";
	public const string Citizen = "models/citizen/citizen.vmdl";
	public const string DefaultMat = "materials/default.vmat";

	static Model _box;
	static Model _plane;
	static Model _citizen;
	static Material _mat;

	public static Model BoxModel => _box ??= Model.Load( Box );
	public static Model PlaneModel => _plane ??= Model.Load( Plane );
	public static Model CitizenModel => _citizen ??= Model.Load( Citizen );
	public static Material TintMat => _mat ??= Material.Load( DefaultMat );

	public static GameObject BoxAt( string name, Vector3 pos, Vector3 scale, Color tint, GameObject parent = null, bool collider = true )
	{
		var go = new GameObject( true, name );
		if ( parent is not null )
			go.SetParent( parent, false );
		go.LocalPosition = parent is null ? default : pos;
		if ( parent is null )
			go.WorldPosition = pos;
		go.LocalScale = scale;

		var mr = go.Components.Create<ModelRenderer>();
		mr.Model = BoxModel;
		mr.MaterialOverride = TintMat;
		mr.Tint = tint;

		if ( collider )
		{
			var col = go.Components.Create<BoxCollider>();
			col.Scale = new Vector3( 50, 50, 50 );
			col.Static = parent is null;
		}

		return go;
	}

	public static GameObject PlaneAt( string name, Vector3 pos, Vector3 scale, Color tint, bool collider = true )
	{
		var go = new GameObject( true, name );
		go.WorldPosition = pos;
		go.LocalScale = scale;

		var mr = go.Components.Create<ModelRenderer>();
		mr.Model = PlaneModel;
		mr.MaterialOverride = TintMat;
		mr.Tint = tint;

		if ( collider )
		{
			var col = go.Components.Create<BoxCollider>();
			col.Center = new Vector3( 0, 0, -4 );
			col.Scale = new Vector3( 100, 100, 8 );
			col.Static = true;
		}

		return go;
	}

	public static GameObject Person( string name, Vector3 pos, Color tint, float scale = 1f )
	{
		var go = new GameObject( true, name );
		go.WorldPosition = pos;
		go.LocalScale = scale;

		try
		{
			var skin = go.Components.Create<SkinnedModelRenderer>();
			skin.Model = CitizenModel;
			skin.Tint = tint;
			skin.UseAnimGraph = true;
		}
		catch
		{
			BoxAt( "body", Vector3.Up * 36 * scale, new Vector3( 0.4f, 0.25f, 0.9f ) * scale, tint, go, false );
		}

		var col = go.Components.Create<BoxCollider>();
		col.Center = Vector3.Up * 36 * scale;
		col.Scale = new Vector3( 20, 20, 72 ) * scale;
		col.Static = true;
		return go;
	}
}