ui/UnitHealthbar.razor

A Razor UI component that renders a world-space unit healthbar. It computes colors, fill percentages, armor display and positions the WorldPanel based on camera / FPS mode, then outputs HTML with inline styles reflecting health, delta and armor.

File Access
@namespace Sandbox
@using Sandbox;
@using Sandbox.UI;
@using System;
@inherits PanelComponent
@attribute [StyleSheet("UnitHealthbar.razor.scss")]

@{
	if (!Unit.IsValid() || Manager.Instance == null)
		return;

	Player player = Unit as Player;

	Color bgColor = player.IsValid() && !(player.Health > 1f)
		? Color.Lerp(new Color(0f, 0f, 0f, 0.8f), new Color(0.5f, 0f, 0f, 0.8f), Utils.FastSin(RealTime.Now * 16f))
		: new Color(0f, 0f, 0f, 0.8f);

	float fillHpPercent = player.IsValid() ? Math.Max(Unit.HpPercent, 0.02f) : Unit.HpPercent;
	bool hpBarHidden = player.IsValid() && player == Manager.Instance.LocalPlayer && player.Stats[ PlayerStat.HpBarHidden ] > 0f;

	// Round so near-1 HpPercent (float imprecision) can't yield a tiny ~2.98e-5 value that
	// .NET formats in scientific notation (e.g. "2.9802322E-05"), which the style parser rejects.
	float deltaRight = MathF.Round( (1f - Unit.HpPercent) * 100f, 3 );
	float fillRight = MathF.Round( (1f - fillHpPercent) * 100f, 3 );
}

<root style="opacity:@(Unit.IsDying || Manager.Instance.GameState == GameState.Lobby ? 0f : 1f);">
	<div class="container">
		<div class="health" style="opacity:@(Unit.HealthbarOpacity)">
			<div class="healthbar" style="background-color: @bgColor.Rgba;">
				@if ( hpBarHidden )
				{
					<div class="heathbarfill" style="right: 0%; background-color: #7a0040ff;"></div>
				}
				else
				{
					<div class="heathbardelta" style="right:@(deltaRight)%;"></div>
					<div class="heathbarfill" style="right:@(fillRight)%;"></div>
				}
			</div>
		</div>

		@if(Unit.Armor > 0)
		{
			var color = Color.Lerp(new Color(1f, 0.8f, 0.8f, 1f), new Color(0.65f, 0.65f, 0.65f, 0.75f), Utils.Map(Unit.RealTimeSinceArmorChanged, 0f, 0.5f, 0f, 1f, EasingType.QuadOut));
			var opacity = Utils.Map(Unit.RealTimeSinceArmorChanged, 0f, 0.5f, 1f, 0.5f, EasingType.QuadOut);
			@* var fontSize = Utils.Map(Unit.RealTimeSinceArmorChanged, 0f, 0.5f, 80f, 60f, EasingType.QuadOut); *@
			var scale = Utils.Map(Unit.RealTimeSinceArmorChanged, 0f, 0.5f, 1.3f, 1f, EasingType.QuadOut);
			<label class="armor_text" text="@($"{(int)Unit.Armor}⛊")" style="color:@(color.Rgba); opacity: @(opacity * Unit.HealthbarArmorOpacity); transform: scale(@scale);" />
		}
	</div>
</root>

@code {
	[Property] public Sandbox.WorldPanel WorldPanel { get; set; }

	public Unit Unit { get; set; }
	// public float Opacity { get; set; }

	protected override void OnStart()
	{
		base.OnStart();

	}

	protected override void OnUpdate()
	{
		base.OnUpdate();

		if (!Unit.IsValid())
			Unit = GetComponentInParent<Unit>();

		if (!Unit.IsValid())
			return;

		WorldPanel.PanelSize = new Vector2(Unit.HealthbarWidth, 500);

		var localPlayer = Manager.Instance.LocalPlayer;
		bool fpsMode = localPlayer.IsValid() && localPlayer.GetSyncStat( PlayerStat.FpsMode ) > 0f;
		if ( fpsMode )
		{
			var cam = Manager.Instance.Camera;
			var toCamera = cam.WorldPosition - WorldPanel.WorldPosition;
			WorldPanel.WorldRotation = Rotation.LookAt( toCamera, Vector3.Up );


			if(Unit == localPlayer)
				WorldPanel.LocalPosition = Vector3.Up * Unit.HealthbarOffset * 0.3f;
			else
				WorldPanel.LocalPosition = Vector3.Up * Unit.HealthbarOffset;
		}
		else
		{
			WorldPanel.WorldRotation = Rotation.From( -55f, -90f, 0f );
			WorldPanel.LocalPosition = Vector3.Up * Unit.HealthbarOffset;
		}
	}

	protected override int BuildHash()
	{
		if (!Unit.IsValid())
			return 0;

		var player = Unit as Player;

		var armor = Unit.Armor;
		var sinceArmorChange = Unit.RealTimeSinceArmorChanged.Relative < 0.5f ? Unit.RealTimeSinceArmorChanged.Relative : 0f;
		var oneHpHash = player.IsValid() && !(player.Health > 1f) ? RealTime.Now : 0f;
		bool hpBarHidden = player.IsValid() && player == Manager.Instance.LocalPlayer && player.Stats[PlayerStat.HpBarHidden] > 0f;

		return HashCode.Combine(Unit.HpPercent, armor, sinceArmorChange, oneHpHash, Unit.IsDying, Unit.HealthbarOpacity, Manager.Instance.GameState, hpBarHidden);
	}
}