Skip to content

Commit

Permalink
Merge pull request #53 from qwqtoday/chat-fix
Browse files Browse the repository at this point in the history
nbt text component implemention
  • Loading branch information
psu-de authored Jul 8, 2024
2 parents 95798fc + 0cb9f29 commit 301efc5
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 18 deletions.
123 changes: 119 additions & 4 deletions Components/MineSharp.ChatComponent/Chat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Text.RegularExpressions;
using MineSharp.Data;
using Newtonsoft.Json;
using fNbt;
using System.Diagnostics;

namespace MineSharp.ChatComponent;

Expand All @@ -16,12 +18,17 @@ namespace MineSharp.ChatComponent;
/// <summary>
/// Represents a Chat Message object
/// </summary>
public class Chat
public partial class Chat
{
/// <summary>
/// The raw Json message
/// </summary>
public string Json { get; }
public string? Json { get; private set; }

/// <summary>
/// The raw NBT Tag message
/// </summary>
public NbtTag? NbtTag { get; private set; }

/// <summary>
/// The message without any styling
Expand All @@ -36,6 +43,9 @@ public class Chat

private readonly MinecraftData data;

[GeneratedRegex(@"\\§[0-9a-fk-r]")]
private static partial Regex FormatTagRegex();

/// <summary>
/// Create a new ChatComponent
/// </summary>
Expand All @@ -49,7 +59,7 @@ public Chat(string json, MinecraftData data)
try
{
this.StyledMessage = this.ParseComponent(JToken.Parse(this.Json));
this.Message = Regex.Replace(this.StyledMessage, "\\$[0-9a-fk-r]", "");
this.Message = FormatTagRegex().Replace(this.StyledMessage, "");
}
catch (JsonReaderException)
{
Expand All @@ -58,6 +68,27 @@ public Chat(string json, MinecraftData data)
}
}

/// <summary>
/// Create a new ChatComponent with nbt tag
/// </summary>
/// <param name="nbt"></param>
/// <param name="data"></param>
public Chat(NbtTag nbt, MinecraftData data)
{
this.NbtTag = nbt;
this.data = data;

try
{
this.StyledMessage = this.ParseComponent(nbt);
this.Message = Regex.Replace(this.StyledMessage, "\\§[0-9a-fk-r]", "");
} catch
{
this.StyledMessage = this.NbtTag.ToString();
this.Message = this.StyledMessage;
}
}

private string ParseComponent(JToken token, string styleCode = "")
{
return token.Type switch
Expand All @@ -70,6 +101,18 @@ private string ParseComponent(JToken token, string styleCode = "")
};
}

private string ParseComponent(NbtTag nbt, string styleCode = "")
{
return nbt.TagType switch
{
NbtTagType.List => ParseArray((NbtList)nbt, styleCode),
NbtTagType.Compound => ParseObject((NbtCompound) nbt, styleCode),
NbtTagType.String => nbt.StringValue,
NbtTagType.Int => nbt.StringValue,
_ => throw new Exception($"Type {nbt.TagType} is not supported")
}; ;
}

private string ParseObject(JObject jObject, string styleCode = "")
{
var sb = new StringBuilder();
Expand Down Expand Up @@ -125,6 +168,67 @@ private string ParseObject(JObject jObject, string styleCode = "")
+ sb.ToString();
}

private string ParseObject(NbtCompound nbt, string styleCode = "")
{
if (nbt.Names.First() == "")
{
return nbt[""].StringValue;
}

var sb = new StringBuilder();

var colorProp = nbt["color"];
if (colorProp != null)
{
var color = ParseComponent(colorProp.StringValue);
var style = TextStyle.GetTextStyle(color);
styleCode = style != null
? style.ToString()
: string.Empty;
}

var extraProp = nbt["extra"];
if (extraProp != null)
{
var extras = (NbtList)extraProp!;

foreach (var item in extras)

sb.Append(this.ParseComponent(item, styleCode) + "§r");
}

var textProp = nbt["text"];
var translateProp = nbt["translate"];

if (textProp != null)
{
return styleCode + ParseComponent(textProp, styleCode) + sb.ToString();
}

if (translateProp == null)
return sb.ToString();

var usingData = new List<string>();

var usingProp = nbt["using"];
var withProp = nbt["with"];
if (usingProp != null && withProp == null)
withProp = usingProp;

if (withProp != null)
{
var array = (NbtList)withProp;
for (int i = 0; i < array.Count; i++)
{
usingData.Add(this.ParseComponent(array[i], styleCode));
}
}

var ruleName = this.ParseComponent(translateProp);
return styleCode + TranslateString(ruleName, usingData.ToArray(), this.data)
+ sb.ToString();
}

private string ParseArray(JArray jArray, string styleCode = "")
{
var sb = new StringBuilder();
Expand All @@ -136,6 +240,17 @@ private string ParseArray(JArray jArray, string styleCode = "")
return sb.ToString();
}

private string ParseArray(NbtList nbtList, string styleCode = "")
{
var sb = new StringBuilder();
foreach (var token in nbtList)
{
sb.Append(ParseComponent(token, styleCode));
}

return sb.ToString();
}

/// <summary>
/// Translate a string using the given rule and format strings.
/// </summary>
Expand All @@ -158,5 +273,5 @@ public static string TranslateString(string ruleName, string[] usings, Minecraft
}

/// <inheritdoc />
public override string ToString() => this.Json;
public override string ToString() => this.Json ?? this.NbtTag!.ToString();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MineSharp.Core.Common;
using MineSharp.Data;
using MineSharp.Data.Protocol;

namespace MineSharp.Protocol.Packets.Clientbound.Play;

#pragma warning disable CS1591
public class SetPassengersPacket : IPacket
{
public PacketType Type => PacketType.CB_Play_SetPassengers;

public int EntityId { get; set; }

public int[] PassengersId { get; set; }

public SetPassengersPacket(int entityId, int[] passengersId)
{
EntityId = entityId;
PassengersId = passengersId;
}

public void Write(PacketBuffer buffer, MinecraftData version)
{
buffer.WriteVarInt(this.EntityId);
buffer.WriteVarIntArray(this.PassengersId, (buf, elem) => buffer.WriteVarInt(elem));
}

public static IPacket Read(PacketBuffer buffer, MinecraftData version)
{
return new SetPassengersPacket(
buffer.ReadVarInt(),
buffer.ReadVarIntArray<int>(buf => buf.ReadVarInt()));
}
}
#pragma warning restore CS1591
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using MineSharp.ChatComponent;
using MineSharp.Core.Common;
using MineSharp.Data;
using MineSharp.Data.Protocol;
Expand All @@ -9,6 +10,7 @@ public class SystemChatMessagePacket : IPacket
public PacketType Type => PacketType.CB_Play_SystemChat;

public string Content { get; set; }
public Chat? Message { get; set; }
public int? ChatType { get; set; }
public bool? IsOverlay { get; set; }

Expand All @@ -28,11 +30,19 @@ public SystemChatMessagePacket(string content, int chatType)
/// </summary>
/// <param name="content"></param>
/// <param name="isOverlay"></param>
public SystemChatMessagePacket(string content, bool isOverlay)
/// <param name="message"></param>
public SystemChatMessagePacket(string content, bool isOverlay, Chat? message = null)
{
this.Message = message;
this.Content = content;
this.IsOverlay = isOverlay;
}
public SystemChatMessagePacket(Chat message, bool isOverlay)
{
this.Message = message;
this.Content = message.StyledMessage;
this.IsOverlay = isOverlay;
}

public void Write(PacketBuffer buffer, MinecraftData version)
{
Expand All @@ -45,11 +55,25 @@ public void Write(PacketBuffer buffer, MinecraftData version)

public static IPacket Read(PacketBuffer buffer, MinecraftData version)
{
var content = buffer.ReadString();
if (version.Version.Protocol >= ProtocolVersion.V_1_19_2)
return new SystemChatMessagePacket(content, buffer.ReadBool());
if (version.Version.Protocol < ProtocolVersion.V_1_20_3)
{
var content = buffer.ReadString();
if (version.Version.Protocol >= ProtocolVersion.V_1_19_2)
return new SystemChatMessagePacket(content, buffer.ReadBool());

return new SystemChatMessagePacket(content, buffer.ReadVarInt());
return new SystemChatMessagePacket(content, buffer.ReadVarInt());
} else
{
var content = buffer.ReadNbt();
try
{
var message = new Chat(content!, version);
return new SystemChatMessagePacket(message, buffer.ReadBool());
} catch
{
return new SystemChatMessagePacket(content!.ToString(), buffer.ReadBool());
}
}
}
}
#pragma warning restore CS1591
3 changes: 2 additions & 1 deletion Components/MineSharp.Protocol/Packets/PacketPalette.cs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ private static void InitializePackets()
RegisterPacket<ChunkBatchFinishedPacket>(PacketType.CB_Play_ChunkBatchFinished);
RegisterPacket<PlayPingPacket>(PacketType.CB_Play_Ping);
RegisterPacket<PlayDisconnectPacket>(PacketType.CB_Play_KickDisconnect);

RegisterPacket<SetPassengersPacket>(PacketType.CB_Play_SetPassengers);

RegisterPacket<SBKeepAlivePacket>(PacketType.SB_Play_KeepAlive);
RegisterPacket<SetPlayerPositionPacket>(PacketType.SB_Play_Position);
RegisterPacket<SetPlayerPositionAndRotationPacket>(PacketType.SB_Play_PositionLook);
Expand Down
19 changes: 15 additions & 4 deletions MineSharp.Bot/Plugins/ChatPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using MineSharp.Bot.Chat;
using MineSharp.Bot.Chat;
using MineSharp.Commands;
using MineSharp.Core.Common;
using MineSharp.Protocol.Packets.Clientbound.Play;
Expand Down Expand Up @@ -469,7 +469,7 @@ private Task HandleChatMessagePacket(PlayerChatPacket packet)
(UUID sender, string message, int type) = packet.Body switch
{
PlayerChatPacket.V1_19Body v19 => (v19.Sender, v19.SignedChat, v19.MessageType),
PlayerChatPacket.V1_19_2_3Body v19_2 => (v19_2.Sender, v19_2.PlainMessage, v19_2.Type),
PlayerChatPacket.V1_19_2_3Body v19_2 => (v19_2.Sender, v19_2.UnsignedContent ?? v19_2.FormattedMessage ?? v19_2.PlainMessage, v19_2.Type),
_ => throw new UnreachableException()
};

Expand Down Expand Up @@ -497,8 +497,14 @@ private Task HandleSystemChatMessage(SystemChatMessagePacket packet)
? ChatMessageType.GameInfo
: ChatMessageType.SystemMessage;
}

this.HandleChatInternal(null, packet.Content, type);
if (packet.Message != null)
{
this.HandleChatInternal(null, packet.Message, type);
}
else
{
this.HandleChatInternal(null, packet.Content, type);
}
return Task.CompletedTask;
}

Expand Down Expand Up @@ -528,6 +534,11 @@ private void HandleChatInternal(UUID? sender, string message, ChatMessageType ty
this.OnChatMessageReceived?.Invoke(this.Bot, sender, new ChatComponent.Chat(message, this.Bot.Data), type, senderName);
}

private void HandleChatInternal(UUID? sender, ChatComponent.Chat message, ChatMessageType type, string? senderName = null)
{
this.OnChatMessageReceived?.Invoke(this.Bot, sender, message, type, senderName);
}

private ChatMessageType GetChatMessageTypeFromRegistry(int index)
{
var val = this.Bot.Registry["minecraft:chat_type"]["value"][index]["name"]!.StringValue!;
Expand Down
Loading

0 comments on commit 301efc5

Please sign in to comment.