/* ┌──────────────────────────────────────────────────────────────────┐ │ Author: Ivan Murzak (https://github.com/IvanMurzak) │ │ Repository: GitHub (https://github.com/IvanMurzak/Unity-MCP) │ │ Copyright (c) 2025 Ivan Murzak │ │ Licensed under the Apache License, Version 2.0. │ │ See the LICENSE file in the project root for more information. │ └──────────────────────────────────────────────────────────────────┘ */ #nullable enable using System.Globalization; using System.Text.Json; using System.Text.Json.Serialization; using UnityEngine; namespace com.IvanMurzak.Unity.MCP.JsonConverters { /// /// Provides shared helper methods for reading and writing floating-point values and Vector3 types /// with support for special floating-point literals (NaN, Infinity, -Infinity). /// public static class JsonFloatHelper { /// /// Reads a float value from the JSON reader, supporting named floating-point literals /// (NaN, Infinity, -Infinity) when enabled in options. /// public static float ReadFloat(ref Utf8JsonReader reader, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { if ((options.NumberHandling & JsonNumberHandling.AllowNamedFloatingPointLiterals) != 0) { var s = reader.GetString(); if (s == "NaN") return float.NaN; if (s == "Infinity") return float.PositiveInfinity; if (s == "-Infinity") return float.NegativeInfinity; throw new JsonException($"Unrecognized floating-point literal: '{s}'. Expected 'NaN', 'Infinity', or '-Infinity'."); } throw new JsonException($"String token encountered but AllowNamedFloatingPointLiterals is not enabled. Value: '{reader.GetString()}'."); } return reader.GetSingle(); } /// /// Writes a float value with the given property name, using string representation /// for special values (NaN, Infinity) when enabled in options. /// public static void WriteFloat(Utf8JsonWriter writer, string propertyName, float value, JsonSerializerOptions options) { if (float.IsNaN(value) || float.IsInfinity(value)) { if ((options.NumberHandling & JsonNumberHandling.AllowNamedFloatingPointLiterals) != 0) { writer.WriteString(propertyName, value.ToString(CultureInfo.InvariantCulture)); return; } } writer.WriteNumber(propertyName, value); } /// /// Reads a Vector3 from the JSON reader. /// public static Vector3 ReadVector3(ref Utf8JsonReader reader, JsonSerializerOptions options) { if (reader.TokenType != JsonTokenType.StartObject) throw new JsonException("Expected start of object token for Vector3."); float x = 0, y = 0, z = 0; while (reader.Read()) { if (reader.TokenType == JsonTokenType.EndObject) return new Vector3(x, y, z); if (reader.TokenType == JsonTokenType.PropertyName) { var propertyName = reader.GetString(); reader.Read(); switch (propertyName) { case "x": x = ReadFloat(ref reader, options); break; case "y": y = ReadFloat(ref reader, options); break; case "z": z = ReadFloat(ref reader, options); break; default: throw new JsonException($"Unexpected property name: {propertyName}. " + "Expected 'x', 'y', or 'z'."); } } } throw new JsonException("Expected end of object token for Vector3."); } /// /// Writes a Vector3 to the JSON writer. /// public static void WriteVector3(Utf8JsonWriter writer, Vector3 value, JsonSerializerOptions options) { writer.WriteStartObject(); WriteFloat(writer, "x", value.x, options); WriteFloat(writer, "y", value.y, options); WriteFloat(writer, "z", value.z, options); writer.WriteEndObject(); } } }