massive/client/chat/ChatWindow.cs
2025-05-22 15:48:46 -04:00

136 lines
3.8 KiB
C#

using Godot;
using SpacetimeDB;
using SpacetimeDB.Types;
public partial class ChatWindow : VBoxContainer
{
const string SystemColor = "#747474";
private LineEdit _userNameInput;
private ChatLog _log;
private LineEdit _input;
// Called when the node enters the scene tree for the first time.
public override void _EnterTree()
{
_userNameInput = GetNode<LineEdit>("Options/Username");
_log = GetNode<ChatLog>("ChatLog");
_input = GetNode<LineEdit>("ChatInput");
_log.Text = "";
}
string UserNameOrIdentity(User user)
{
return user != null ? user.Name ?? user.Identity.ToString()[..8] : "unknown";
}
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
DbConnection conn = Spacetime.Instance.Connection;
_userNameInput.TextSubmitted += OnUsernameInput;
_userNameInput.FocusExited += ResetUsername;
_input.TextSubmitted += OnMessageInput;
conn.Db.User.OnInsert += User_OnInsert;
conn.Db.User.OnUpdate += User_OnUpdate;
conn.Db.Message.OnInsert += Message_OnInsert;
conn.Reducers.OnSetName += Reducer_OnSetNameEvent;
conn.Reducers.OnSendMessage += Reducer_OnSendMessageEvent;
}
void ResetUsername()
{
_userNameInput.Text = UserNameOrIdentity(Spacetime.Instance.Me);
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
private void OnUsernameInput(string text)
{
Spacetime.Instance.Connection.Reducers.SetName(text);
}
private void OnMessageInput(string text)
{
Spacetime.Instance.Connection.Reducers.SendMessage(text);
_input.Text = "";
}
void User_OnInsert(EventContext ctx, User insertedValue)
{
if (ctx.Event is Event<Reducer>.SubscribeApplied)
{
if (insertedValue.Identity == Spacetime.Instance.Identity)
{
ResetUsername();
}
return;
}
_log.PushMessage("System", $"{UserNameOrIdentity(insertedValue)} connected", SystemColor);
}
void User_OnUpdate(EventContext ctx, User oldValue, User newValue)
{
if (oldValue.Name != newValue.Name)
{
_log.PushMessage("System", $"{UserNameOrIdentity(oldValue)} renamed to {UserNameOrIdentity(newValue)}", SystemColor);
}
if (oldValue.Online != newValue.Online)
{
if (newValue.Online)
{
_log.PushMessage("System", $"{UserNameOrIdentity(newValue)} connected", SystemColor);
}
else
{
_log.PushMessage("System", $"{UserNameOrIdentity(newValue)} disconnected", SystemColor);
}
}
}
void Message_OnInsert(EventContext ctx, Message insertedValue)
{
User sender = ctx.Db.User.Identity.Find(insertedValue.Sender);
string color = sender.Identity.Equals(Spacetime.Instance.Identity) ? "blue" : "red";
if (ctx.Event is Event<Reducer>.SubscribeApplied)
{
_log.PushMessage(UserNameOrIdentity(sender), insertedValue.Text, color);
return;
}
_log.PushMessage(UserNameOrIdentity(sender), insertedValue.Text, color);
}
/// Our `OnSetNameEvent` callback: print a warning if the reducer failed.
void Reducer_OnSetNameEvent(ReducerEventContext ctx, string name)
{
var e = ctx.Event;
if (e.CallerIdentity != Spacetime.Instance.Identity)
{
// Not me
return;
}
if (e.Status is Status.Failed(var error))
{
GD.PrintErr($"Failed to change name to {name}: {error}");
return;
}
}
/// Our `OnSendMessageEvent` callback: print a warning if the reducer failed.
void Reducer_OnSendMessageEvent(ReducerEventContext ctx, string text)
{
var e = ctx.Event;
if (e.CallerIdentity == Spacetime.Instance.Identity && e.Status is Status.Failed(var error))
{
GD.PrintErr($"Failed to send message {text}: {error}");
}
}
}