OMRWeaponMetadata.cs
using Sandbox;
using System;
using System.Collections.Generic;

/// <summary>
/// Stable gameplay archetype for OMR weapon selection.
///
/// This is intentionally broader than a weapon's exact identity:
/// - WeaponId identifies one exact weapon ("usp", "mp5", "m4a1").
/// - WeaponArchetype lets future round presets ask for a class
///   ("any shotgun", "any sniper") without relying on prefab filenames.
///
/// Mechanical facts that already exist in BaseCombatWeapon, such as
/// PrimaryAutomatic or Ballistics.Pellets, are NOT duplicated here.
/// </summary>
public enum OMRWeaponArchetype
{
	Unknown,
	Pistol,
	SubmachineGun,
	AssaultRifle,
	Shotgun,
	SniperRifle,
	Revolver,
	Special
}

/// <summary>
/// Small, dependency-free helper layer around weapon prefab metadata.
///
/// Round rules and modifier selection can use this instead of knowing about
/// prefab filenames or duplicating component lookups throughout the project.
/// </summary>
public static class OMRWeaponUtility
{
	public static OneMoreRoundWeapon GetWeapon(
		GameObject prefab
	)
	{
		if (
			prefab is null ||
			!prefab.IsValid
		)
		{
			return null;
		}

		return prefab.Components.Get<OneMoreRoundWeapon>(
			FindMode.InSelf |
			FindMode.InDescendants
		);
	}

	public static string GetWeaponId(
		GameObject prefab
	)
	{
		OneMoreRoundWeapon weapon =
			GetWeapon(
				prefab
			);

		if ( weapon is null )
			return string.Empty;

		if (
			weapon.Definition is not null &&
			weapon.Definition.IsValid &&
			!string.IsNullOrWhiteSpace( weapon.Definition.WeaponId )
		)
		{
			return weapon.Definition.WeaponId.Trim();
		}

		if ( string.IsNullOrWhiteSpace( weapon.WeaponId ) )
			return string.Empty;

		return weapon.WeaponId.Trim();
	}

	public static string GetDisplayName(
		GameObject prefab
	)
	{
		OneMoreRoundWeapon weapon =
			GetWeapon(
				prefab
			);

		if ( weapon is not null )
		{
			if (
				weapon.Definition is not null &&
				weapon.Definition.IsValid &&
				!string.IsNullOrWhiteSpace( weapon.Definition.DisplayName )
			)
			{
				return weapon.Definition.DisplayName.Trim();
			}

			if ( !string.IsNullOrWhiteSpace( weapon.DisplayName ) )
				return weapon.DisplayName.Trim();
		}

		if (
			prefab is not null &&
			prefab.IsValid &&
			!string.IsNullOrWhiteSpace(
				prefab.Name
			)
		)
		{
			return prefab.Name
				.Replace(
					"_",
					" "
				)
				.Trim();
		}

		return "Unknown Weapon";
	}

	public static bool MatchesArchetype(
		GameObject prefab,
		OMRWeaponArchetype archetype
	)
	{
		OneMoreRoundWeapon weapon =
			GetWeapon(
				prefab
			);

		if ( weapon is null )
			return false;

		OMRWeaponArchetype candidate =
			weapon.Definition is not null && weapon.Definition.IsValid
				? weapon.Definition.Archetype
				: weapon.WeaponArchetype;

		return candidate == archetype;
	}

	public static GameObject FindById(
		IEnumerable<GameObject> prefabs,
		string weaponId
	)
	{
		if (
			prefabs is null ||
			string.IsNullOrWhiteSpace(
				weaponId
			)
		)
		{
			return null;
		}

		foreach (
			GameObject prefab in prefabs
		)
		{
			string candidate =
				GetWeaponId(
					prefab
				);

			if (
				string.Equals(
					candidate,
					weaponId,
					StringComparison.OrdinalIgnoreCase
				)
			)
			{
				return prefab;
			}
		}

		return null;
	}
}