ui/PlayerPerks.razor

Razor UI component that renders a player's perk icons. It chooses either the selected player or local player, computes a panel height, and displays either synced proxy perks as PerkIconStatic or local perks as PerkIcon with small random rotation per icon. It overrides BuildHash to drive re-rendering based on player, perk count, perk hash and game over state.

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

@{
	var player = Manager.Instance.SelectedPlayer.IsValid()
		? Manager.Instance.SelectedPlayer
		: Manager.Instance.LocalPlayer;

	if (!player.IsValid())
		return;

	var height = Manager.Instance.Players.Count > 1 ? 880f : 950f;
}

<root style="height: @(height)px; max-height: @(height)px;">
	@if( player.IsProxy )
	{
		if (player.SyncPerks.Count == 0)
			return;

		int index = 0;
		<div class="itemlist" style="opacity:@(1f);">
			@foreach (var pair in player.SyncPerks)
			{
				var rot = Utils.Map((player.PerkRandomRotationSeed + index * 3f) % 10, 0, 9, -5f, 5f);
				<PerkIconStatic style="width: 50px; height: 50px; transform: rotate(@(rot)deg);" PerkType=@(PerkManager.IdentityToType(pair.Key)) Level=@(pair.Value) ProgressLevel=@(pair.Value) Banished=@false />

				index++;
			}
		</div>
	}
	else
	{
		if (player.Perks.Count == 0)
			return;

		int index = 0;
		<div class="itemlist @(Manager.Instance.IsGameOver ? "" : "itemlist_hover")">
			@foreach (var (_, perk) in player.Perks)
			{
				var rot = Utils.Map((player.PerkRandomRotationSeed + index * 3f) % 10, 0, 9, -5f, 5f);
				<PerkIcon style="width: 50px; height: 50px;" Perk=@perk Angle=@rot Banished=@false />

				index++;
			}
		</div>
	}
</root>

@code
{
	protected override int BuildHash()
	{
		var player = Manager.Instance.SelectedPlayer.IsValid()
			? Manager.Instance.SelectedPlayer
			: Manager.Instance.LocalPlayer;

		var perkHash = player.IsValid()
			? player.PerkHash
			: 0;

		var perkCount = player.IsValid()
			? player.SyncPerks.Count
			: 0;

		return HashCode.Combine(
			player, 
			// player.Id // todo: this instead?
			perkCount,
			perkHash,
			Manager.Instance.IsGameOver
			// Time.Now
		);
	}
}