implement client side

This commit is contained in:
Benjamin Palko 2025-05-21 14:35:09 -04:00
parent 4e94f8d7fb
commit 6958d16bfa
17 changed files with 415 additions and 0 deletions

20
client/chat/ChatLog.cs Normal file
View file

@ -0,0 +1,20 @@
using Godot;
public partial class ChatLog : RichTextLabel
{
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
}
public void PushMessage(string name, string message, string color)
{
string entry = $"[color={color}]{name}:[/color] {message}";
this.Text += $"{entry}\n";
}
}

View file

@ -0,0 +1 @@
uid://cgn6wa7td0ekp

136
client/chat/ChatWindow.cs Normal file
View file

@ -0,0 +1,136 @@
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}");
}
}
}

View file

@ -0,0 +1 @@
uid://c3s41dv7hv4md

View file

@ -0,0 +1,40 @@
[gd_scene load_steps=3 format=3 uid="uid://cqmy41vtnqd6f"]
[ext_resource type="Script" uid="uid://c3s41dv7hv4md" path="res://chat/ChatWindow.cs" id="1_d8jvm"]
[ext_resource type="Script" uid="uid://cgn6wa7td0ekp" path="res://chat/ChatLog.cs" id="2_fkxbv"]
[node name="Chat Window" type="VBoxContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_d8jvm")
[node name="Options" type="HBoxContainer" parent="."]
layout_mode = 2
alignment = 2
[node name="Label" type="Label" parent="Options"]
layout_mode = 2
text = "Username:"
[node name="Username" type="LineEdit" parent="Options"]
custom_minimum_size = Vector2(120, 0)
layout_mode = 2
[node name="ColorPickerButton" type="ColorPickerButton" parent="Options"]
layout_mode = 2
text = "Color"
[node name="ChatLog" type="RichTextLabel" parent="."]
layout_mode = 2
size_flags_vertical = 3
bbcode_enabled = true
text = "BBCode [color=green]test[/color]"
scroll_following = true
vertical_alignment = 2
script = ExtResource("2_fkxbv")
[node name="ChatInput" type="LineEdit" parent="."]
layout_mode = 2