Weapons/Weapon.cs
/// <summary>
/// Base weapon — attaches to a GameObject and delegates to WeaponComponents.
/// </summary>
[Title( "Weapon" ), Icon( "track_changes" )]
public sealed partial class Weapon : Component
{
	[Property, ResourceType( "png" )] public string IconPath { get; set; }

	private PlayerPawn _player;

	/// <summary>
	/// The owning player. Set explicitly by the host on deploy; lazily resolved from
	/// ancestor hierarchy on clients where the assign RPC hasn't run.
	/// </summary>
	public PlayerPawn Player
	{
		get => _player ??= Components.Get<PlayerPawn>( FindMode.InAncestors );
		set => _player = value;
	}

	/// <summary>
	/// Aim ray from the owning player (forwarded from the ship's position/rotation).
	/// </summary>
	public Ray AimRay => new Ray( Player?.WorldPosition ?? WorldPosition, Player?.WorldRotation.Forward ?? WorldRotation.Forward );

	protected override void OnStart()
	{
		// Only disable if this is a fresh local spawn (not a replicated copy arriving from host).
		// Replicated weapons arrive with the correct enabled state already applied.
		if ( !Network.Active )
			GameObject.Enabled = false;
	}

	public bool CanHolster( PlayerPawn player ) => true;

	public void OnHolster( PlayerPawn player )
	{
		GameObject.Enabled = false;
	}

	public bool CanDeploy( PlayerPawn player ) => true;

	public void OnDeploy( PlayerPawn player )
	{
		GameObject.SetParent( player.GameObject, false );
		Player = player;
		GameObject.Enabled = true;
	}

	public void Simulate()
	{
		foreach ( var c in Components.GetAll<WeaponComponent>( FindMode.EnabledInSelfAndDescendants ) )
			c.Simulate();
	}

	public void FrameSimulate()
	{
		foreach ( var c in Components.GetAll<WeaponComponent>( FindMode.EnabledInSelfAndDescendants ) )
			c.FrameSimulate();
	}

	public void RunGameEvent( string eventName )
	{
		foreach ( var c in Components.GetAll<WeaponComponent>( FindMode.EnabledInSelfAndDescendants ) )
		{
			if ( c is null || !c.IsValid() ) continue;
			c.OnGameEvent( eventName );
		}
	}

	public void BuildInput()
	{
		foreach ( var c in Components.GetAll<WeaponComponent>( FindMode.EnabledInSelfAndDescendants ) )
			c.BuildInput();
	}

	public override string ToString() => $"Weapon ({GameObject.Name})";
}