UI/Chat.razor
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
@implements Component.INetworkListener
<root>
<div class="output">
@foreach (var entry in Entries)
{
<div class="chat_entry">
@if (entry.steamid > 0)
{
<div class="avatar" style="background-image: url( avatar:@entry.steamid )"></div>
}
<div class="author">@entry.author</div>
<div class="message">@entry.message</div>
</div>
}
</div>
<div class="input">
<TextEntry @ref="InputBox" onsubmit="@ChatFinished"></TextEntry>
</div>
</root>
@code
{
TextEntry InputBox;
public record Entry( ulong steamid, string author, string message, RealTimeSince timeSinceAdded );
List<Entry> Entries = new();
protected override void OnUpdate()
{
if (InputBox is null)
return;
Panel.AcceptsFocus = false;
if ( Input.Pressed( "chat" ) )
{
InputBox.Focus();
}
if ( Entries.RemoveAll( x => x.timeSinceAdded > 20.0f ) > 0 )
{
StateHasChanged();
}
SetClass( "open", InputBox.HasFocus );
}
void ChatFinished()
{
var text = InputBox.Text;
InputBox.Text = "";
if (string.IsNullOrWhiteSpace(text))
return;
AddText( text );
}
[Rpc.Broadcast]
public void AddText( string message )
{
message = message.Truncate( 300 );
if (string.IsNullOrWhiteSpace(message))
return;
var author = Rpc.Caller.DisplayName;
var steamid = Rpc.Caller.SteamId;
Log.Info($"{author}: {message}");
Entries.Add(new Entry(steamid, author, message, 0.0f));
StateHasChanged();
}
[Rpc.Broadcast] // todo: only from host/owner
public void AddSystemText(string message)
{
message = message.Truncate(300);
if (string.IsNullOrWhiteSpace(message))
return;
Entries.Add(new Entry(0, "ℹ️", message, 0.0f));
StateHasChanged();
}
void Component.INetworkListener.OnConnected( Connection channel )
{
if ( IsProxy ) return;
AddSystemText( $"{channel.DisplayName} has joined the game" );
}
void Component.INetworkListener.OnDisconnected( Connection channel )
{
if ( IsProxy ) return;
AddSystemText( $"{channel.DisplayName} has left the game" );
}
}