157 lines
3.5 KiB
Plaintext
157 lines
3.5 KiB
Plaintext
@using Sandbox
|
|
@using System
|
|
@using Sandbox.UI
|
|
@namespace Sandbox
|
|
@inherits PanelComponent
|
|
@implements Component.INetworkListener
|
|
|
|
<root>
|
|
<div class="output">
|
|
@foreach ( var entry in Entries )
|
|
{
|
|
<ChatEntry Type="@entry.Type"
|
|
SteamID="@entry.SteamID"
|
|
Author="@entry.Author"
|
|
Message="@entry.Message"
|
|
IsTemporary="@entry.IsTemporary"/>
|
|
}
|
|
</div>
|
|
|
|
<div class="input-container">
|
|
<TextEntry @ref=" InputBox" onsubmit="@ChatFinished"/>
|
|
</div>
|
|
</root>
|
|
|
|
@code {
|
|
public static Chat Instance;
|
|
public Chat() => Instance = this;
|
|
public static bool IsActive = false;
|
|
|
|
public enum MessageType
|
|
{
|
|
Player,
|
|
System,
|
|
Admin,
|
|
Notification
|
|
}
|
|
|
|
public record Entry
|
|
{
|
|
public Entry( Chat.MessageType type, ulong steamID, string author, string message, RealTimeSince timeSinceAdded, bool isTemporary )
|
|
{
|
|
Type = type;
|
|
SteamID = steamID;
|
|
Author = author;
|
|
Message = message;
|
|
TimeSinceAdded = timeSinceAdded;
|
|
IsTemporary = isTemporary;
|
|
}
|
|
|
|
public Chat.MessageType Type { get; internal set; }
|
|
public ulong SteamID { get; internal set; }
|
|
public string Author { get; internal set; }
|
|
public string Message { get; internal set; }
|
|
public RealTimeSince TimeSinceAdded { get; internal set; }
|
|
public bool IsTemporary { get; internal set; }
|
|
}
|
|
|
|
List<Entry> Entries = new();
|
|
public TextEntry InputBox;
|
|
public event Action<string> OnChat;
|
|
|
|
protected override void OnUpdate()
|
|
{
|
|
if ( InputBox is null ) return;
|
|
Panel.AcceptsFocus = false;
|
|
|
|
if ( Input.Pressed( "chat" ) )
|
|
Open();
|
|
|
|
if ( InputBox.HasFocus && Input.EscapePressed )
|
|
{
|
|
Input.EscapePressed = false;
|
|
ChatClosed();
|
|
}
|
|
|
|
SetClass( "open", InputBox.HasFocus );
|
|
}
|
|
|
|
public static void Open()
|
|
{
|
|
IsActive = true;
|
|
Instance.InputBox?.Focus();
|
|
|
|
foreach ( var entry in Instance.Entries )
|
|
entry.IsTemporary = false;
|
|
|
|
Instance.StateHasChanged();
|
|
}
|
|
|
|
public static void AddMessage( MessageType type, string message, ulong steamId = 0, string author = "" ) => Instance?.AddMessageInternal( type, message, steamId, author );
|
|
|
|
[ConCmd( "say" )]
|
|
public static void Say( string message )
|
|
{
|
|
Instance?.AddTextInternal( message );
|
|
}
|
|
|
|
[Rpc.Broadcast]
|
|
public void AddTextInternal( string message )
|
|
{
|
|
if ( string.IsNullOrWhiteSpace( message ) ) return;
|
|
|
|
AddMessageInternal( MessageType.Player, message.Truncate( 300 ), Rpc.Caller.SteamId, Rpc.Caller.DisplayName );
|
|
}
|
|
|
|
void AddMessageInternal( MessageType type, string message, ulong steamId = 0, string author = "" )
|
|
{
|
|
Entries.Add( new Entry( type, steamId, author, message, 0, !IsActive ) );
|
|
StateHasChanged();
|
|
Log.Info( $"[{type}] {author}: {message}" );
|
|
}
|
|
|
|
void ScrollToBottom()
|
|
{
|
|
var panel = Panel.Children.First();
|
|
panel.ScrollVelocity = 0;
|
|
panel.ScrollOffset = 0;
|
|
}
|
|
|
|
void ChatFinished()
|
|
{
|
|
IsActive = false;
|
|
var text = InputBox.Text;
|
|
InputBox.Text = "";
|
|
|
|
if ( !string.IsNullOrWhiteSpace( text ) )
|
|
{
|
|
OnChat?.Invoke( text );
|
|
AddTextInternal( text );
|
|
}
|
|
|
|
ScrollToBottom();
|
|
OnChat = null;
|
|
}
|
|
|
|
void ChatClosed()
|
|
{
|
|
IsActive = false;
|
|
InputBox.Text = "";
|
|
ScrollToBottom();
|
|
OnChat = null;
|
|
}
|
|
|
|
void Component.INetworkListener.OnConnected( Connection channel )
|
|
{
|
|
if ( IsProxy ) return;
|
|
AddMessageInternal( MessageType.System, $"{channel.DisplayName} has joined the game" );
|
|
}
|
|
|
|
void Component.INetworkListener.OnDisconnected( Connection channel )
|
|
{
|
|
if ( IsProxy ) return;
|
|
AddMessageInternal( MessageType.System, $"{channel.DisplayName} has left the game" );
|
|
}
|
|
|
|
}
|