swb_editor/Commands.cs

Editor command that opens or closes an offsets editor UI for the active weapon. It finds the active Weapon component in the current scene, finds a live PanelComponent to host the UI, toggles an OffsetEditor panel, and sets the weapon ViewModelHandler.EditorMode accordingly.

File Access
using SWB.Base;
using Sandbox;
using System.Linq;

namespace SWB.Editor;

/// <summary>
/// The offset editor — `swb_editor_offsets` opens a panel for dialling in a
/// weapon's aim / run / customize offsets by eye instead of by guesswork.
///
/// ⚠️ MODIFIED FROM UPSTREAM, same reason as swb_base/Commands.cs: it reached
/// into SWB's own `swb_player` module for `PlayerBase.Local`, and this project
/// vendors `swb_base` + `swb_shared` + `swb_editor` only. NZPlayer is the player
/// here.
///
/// ⛔ THIS TOOL IS WORTH KEEPING WORKING. Every ported weapon needs an aim
/// offset found by eye — there is no number in the ARC9 data that maps to it —
/// so across a 135-weapon pack this panel is the difference between a slider
/// and a recompile per attempt.
/// </summary>
internal class Commands
{
	static OffsetEditor offsetEditor;

	[ConCmd( "swb_editor_offsets", Help = "Opens the offsets editor" )]
	public static void OpenOffsetsEditor()
	{
		// ⚠️ The ACTIVE weapon, found by walking the scene rather than through an
		// inventory interface. SWB's own player exposes `Inventory.Active`; ours
		// does not implement IInventory yet, and the editor only needs "the
		// weapon currently enabled under a player".
		var weapon = Game.ActiveScene?
			.GetAllComponents<Weapon>()
			.FirstOrDefault( w => w.IsValid() && w.Active );

		if ( offsetEditor is not null )
		{
			offsetEditor.Delete();
			offsetEditor = null;

			if ( weapon?.ViewModelHandler is not null )
				weapon.ViewModelHandler.EditorMode = false;

			return;
		}

		if ( weapon is null )
		{
			Log.Warning( "[swb] no active weapon — hold one before opening the offset editor" );
			return;
		}

		// ⚠️ HOSTED ON AN EXISTING PanelComponent, which is what upstream's
		// `player.RootDisplay` was — a PanelComponent, NOT a ScreenPanel.
		// ScreenPanel has no `.Panel` to add children to, and reaching for one
		// here compiled in my head and not in the compiler.
		//
		// Any live PanelComponent will do: this is an authoring overlay, and the
		// game HUD is guaranteed to be up whenever a weapon is being held.
		var host = Game.ActiveScene?
			.GetAllComponents<PanelComponent>()
			.FirstOrDefault( p => p.IsValid() && p.Active && p.Panel is not null );

		if ( host is null )
		{
			Log.Warning( "[swb] no UI panel to host the offset editor — is the HUD up?" );
			return;
		}

		offsetEditor = new OffsetEditor( weapon );
		host.Panel.AddChild( offsetEditor );

		if ( weapon.ViewModelHandler is not null )
			weapon.ViewModelHandler.EditorMode = true;
	}
}