Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nbt text component implemention #53

Merged
merged 5 commits into from
Jul 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading