Editor/Decompiler/Formats/IBspFormatDescriptor.cs
namespace BspImport.Decompiler.Formats;

/// <summary>
/// Describes a specific BSP format variant: how to detect it and how to read its structures.
/// Implement this interface to add support for a new BSP game format without modifying
/// existing code. Just register the new descriptor in <see cref="BspFormatRegistry"/>.
/// </summary>
public interface IBspFormatDescriptor
{
	/// <summary>The game format enum value this descriptor represents.</summary>
	BspGameFormat GameFormat { get; }

	/// <summary>
	/// All BSP version numbers this format handles.
	/// A descriptor may support more than one version when a game shipped maps in
	/// multiple format revisions (e.g. HL2 beta shipped v17 and v18 maps).
	/// </summary>
	IReadOnlySet<int> SupportedVersions { get; }

	/// <summary> Human-readable name used in log messages and the import context. </summary>
	string DisplayName { get; }

	/// <summary>
	/// Specificity score used to order competing candidates that share a version number.
	/// The registry tries higher-scoring descriptors before lower-scoring ones.
	/// A descriptor whose <see cref="MatchesEntities"/> always returns <c>true</c>
	/// (broadest fallback) should have score 0.
	///
	/// Suggested scale:
	/// <list type="bullet">
	///   <item>100 — single-game format with unique version (e.g. VTMB v17).</item>
	///   <item>50  — multi-version format or game with distinct entity signatures.</item>
	///   <item>10  — game with weak / shared entity signatures.</item>
	///   <item>0   — broadest catch-all fallback for a version group.</item>
	/// </list>
	/// </summary>
	int SpecificityScore { get; }

	LumpHeaderLayout LumpHeaderLayout { get; }
	BrushSideLayout BrushSideLayout { get; }
	StaticPropLayout StaticPropLayout { get; }

	/// <summary>
	/// Returns the binary struct readers appropriate for the given BSP version number.
	/// Allows a single descriptor to handle multiple versions that have slightly
	/// different layouts (e.g. a hypothetical descriptor for HL2 beta could return
	/// different readers for v17 vs. v18).
	/// </summary>
	/// <param name="bspVersion">The exact version read from the BSP file header.</param>
	IBspStructReaders GetStructReaders( int bspVersion );

	/// <summary>
	/// Fast pre-filter using the map file name or path.
	/// Called before <see cref="MatchesEntities"/> as it requires no lump parsing.
	///
	/// Return <c>true</c> if the map name is consistent with this format (or if this
	/// descriptor has no opinion on naming). Return <c>false</c> only when the name
	/// is a reliable negative signal (e.g. a VTMB-prefix map can't be HL2 beta).
	///
	/// The default implementation should return <c>true</c> (no-op filter).
	/// </summary>
	/// <param name="mapName">
	/// The bare filename without extension, e.g. <c>"la_sewers"</c> or <c>"d1_trainstation_01"</c>.
	/// </param>
	bool MatchesMapName( string mapName );

	/// <summary>
	/// Secondary identification using entity classnames from lump 0.
	/// Only called when multiple descriptors share the same version number.
	/// Return <c>true</c> if the provided entity composition is consistent with this format.
	/// </summary>
	/// <param name="entityClassNames">
	/// Distinct classnames of all entities parsed from lump 0.
	/// </param>
	bool MatchesEntities( IReadOnlyList<string> entityClassNames );
}