ui/FloaterTextDisplay.razor
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent

<root>
	@foreach(var floaterText in Scene.GetAllComponents<FloaterText>())
	{
		var pos = floaterText.WorldPosition;
		var screenPos = Scene.Camera.PointToScreenPixels(pos) * Panel.ScaleFromScreen;

		<div class="text_container" style="left: @(screenPos.x - 200)px; top: @(screenPos.y - 40)px; color:@(floaterText.TextColor.Rgba); opacity:@(floaterText.Opacity); transform: scale( @(floaterText.Scale) );">
			<div class="text" style="font-size:@(floaterText.FontSize);">@(floaterText.Text)</div>

			@if(!string.IsNullOrEmpty(floaterText.EmojiText))
			{
				<div class="emoji" style="font-size:@(floaterText.FontSize * 0.9f);">@(floaterText.EmojiText)</div>
			}
		</div>
	}

	@foreach(var floaterImage in Scene.GetAllComponents<FloaterImage>())
	{
		var pos = floaterImage.WorldPosition;
		var screenPos = Scene.Camera.PointToScreenPixels(pos) * Panel.ScaleFromScreen;

		<div class="image" style="left: @(screenPos.x - 200)px; top: @(screenPos.y - 200)px; opacity:@(floaterImage.Opacity); transform: scale( @(floaterImage.Scale) ); background-image: url(@floaterImage.Filename));">
		</div>
	}

	@foreach(var floaterLock in Scene.GetAllComponents<FloaterLock>())
	{
		var pos = floaterLock.WorldPosition;
		var screenPos = Scene.Camera.PointToScreenPixels(pos) * Panel.ScaleFromScreen;

		<div class="lock" style="left: @(screenPos.x - 91.5)px; top: @(screenPos.y - 70)px; opacity:@(floaterLock.Opacity); transform: scale( @(floaterLock.Scale) ); background-image: url(@($"textures/{(floaterLock.ShowLocked ? "lock" : "lock_unlocked")}.png"));">
			<div class="lock_label">
				@(floaterLock.NumTurns)
			</div>
		</div>
	}
</root>

@code
{

	protected override int BuildHash()
	{
		var floaterHash = Manager.Instance.NumFloaters > 0 ? Time.Now : 0f;

		return System.HashCode.Combine(
			floaterHash
		);
	}
}