Minecraft-Console-Client/MinecraftClient/Json.cs
Anon 757cbe1a68 Fix ParseJson crash on non-JSON plain-text input (e.g. vanilla MOTD)
When the MC server sends a plain-text string (not valid JSON) for fields like
the ServerData MOTD, JsonNode.Parse() throws JsonReaderException. This was a
regression introduced by the System.Text.Json modernization.

Fix: catch JsonException in ParseJson() and return JsonValue.Create(json) so
plain-text strings are treated as literal string values rather than crashing.

Tested against a real Minecraft 1.21.11 server (offline mode): MCC connects
and stays connected without crashing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-22 19:53:15 +01:00

55 lines
No EOL
1.8 KiB
C#

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Nodes;
namespace MinecraftClient;
/// <summary>
/// JSON utilities backed by System.Text.Json.
/// </summary>
public static class Json
{
private static readonly JsonSerializerOptions s_escapeOptions = new()
{
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
/// <summary>
/// Parse a JSON string into a mutable <see cref="JsonNode"/> DOM.
/// Returns null for null, empty, or whitespace-only input.
/// Returns a <see cref="JsonValue"/> wrapping the raw string when the input
/// is not valid JSON (e.g. a plain-text Minecraft MOTD or chat message).
/// </summary>
public static JsonNode? ParseJson(string? json)
{
if (string.IsNullOrWhiteSpace(json)) return null;
try { return JsonNode.Parse(json); }
catch (JsonException) { return JsonValue.Create(json); }
}
/// <summary>
/// Escape a string for embedding inside a JSON string literal.
/// Uses System.Text.Json serialization and strips the surrounding quotes.
/// </summary>
public static string EscapeString(string src) =>
JsonSerializer.Serialize(src, s_escapeOptions)[1..^1];
}
/// <summary>
/// Extension helpers for <see cref="JsonNode"/> that replicate the access patterns
/// of the former <c>JSONData.StringValue</c> property.
/// </summary>
public static class JsonNodeExtensions
{
/// <summary>
/// Return the string representation of any JSON value.
/// Strings are returned without quotes; numbers, booleans, and null
/// are returned as their text representation.
/// </summary>
public static string GetStringValue(this JsonNode? node) => node switch
{
null => "null",
JsonValue val when val.TryGetValue<string>(out var s) => s,
_ => node.ToJsonString()
};
}