mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 18:27:24 +01:00
Fix EQP Entries not deserializing correctly due to C# json bug.
This commit is contained in:
parent
2b0844a21e
commit
2cece9c422
2 changed files with 98 additions and 2 deletions
|
|
@ -6,14 +6,18 @@ using Penumbra.GameData.Enums;
|
|||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Structs;
|
||||
using Penumbra.Meta.Files;
|
||||
using Penumbra.Util;
|
||||
|
||||
namespace Penumbra.Meta.Manipulations;
|
||||
|
||||
[StructLayout( LayoutKind.Sequential, Pack = 1 )]
|
||||
public readonly struct EqpManipulation : IMetaManipulation< EqpManipulation >
|
||||
{
|
||||
public readonly EqpEntry Entry;
|
||||
public readonly ushort SetId;
|
||||
[JsonConverter( typeof( ForceNumericFlagEnumConverter ) )]
|
||||
public readonly EqpEntry Entry;
|
||||
|
||||
public readonly ushort SetId;
|
||||
|
||||
[JsonConverter( typeof( StringEnumConverter ) )]
|
||||
public readonly EquipSlot Slot;
|
||||
|
||||
|
|
|
|||
92
Penumbra/Util/FixedUlongStringEnumConverter.cs
Normal file
92
Penumbra/Util/FixedUlongStringEnumConverter.cs
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
namespace Penumbra.Util;
|
||||
|
||||
// Json.Net has a bug
|
||||
// ulong enums can not be correctly deserialized if they exceed long.MaxValue.
|
||||
// These converters fix this, taken from https://stackoverflow.com/questions/61740964/json-net-unable-to-deserialize-ulong-flag-type-enum/
|
||||
public class ForceNumericFlagEnumConverter : FixedUlongStringEnumConverter
|
||||
{
|
||||
private static bool HasFlagsAttribute( Type? objectType )
|
||||
=> objectType != null && Attribute.IsDefined( Nullable.GetUnderlyingType( objectType ) ?? objectType, typeof( System.FlagsAttribute ) );
|
||||
|
||||
public override void WriteJson( JsonWriter writer, object? value, JsonSerializer serializer )
|
||||
{
|
||||
var enumType = value?.GetType();
|
||||
if( HasFlagsAttribute( enumType ) )
|
||||
{
|
||||
var underlyingType = Enum.GetUnderlyingType( enumType! );
|
||||
var underlyingValue = Convert.ChangeType( value, underlyingType );
|
||||
writer.WriteValue( underlyingValue );
|
||||
}
|
||||
else
|
||||
{
|
||||
base.WriteJson( writer, value, serializer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FixedUlongStringEnumConverter : StringEnumConverter
|
||||
{
|
||||
public override object? ReadJson( JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer )
|
||||
{
|
||||
if( reader.MoveToContentAndAssert().TokenType != JsonToken.Integer || reader.ValueType != typeof( System.Numerics.BigInteger ) )
|
||||
{
|
||||
return base.ReadJson( reader, objectType, existingValue, serializer );
|
||||
}
|
||||
|
||||
// Todo: throw an exception if !this.AllowIntegerValues
|
||||
// https://www.newtonsoft.com/json/help/html/P_Newtonsoft_Json_Converters_StringEnumConverter_AllowIntegerValues.htm
|
||||
var enumType = Nullable.GetUnderlyingType( objectType ) ?? objectType;
|
||||
if( Enum.GetUnderlyingType( enumType ) == typeof( ulong ) )
|
||||
{
|
||||
var bigInteger = ( System.Numerics.BigInteger )reader.Value!;
|
||||
if( bigInteger >= ulong.MinValue && bigInteger <= ulong.MaxValue )
|
||||
{
|
||||
return Enum.ToObject( enumType, checked( ( ulong )bigInteger ) );
|
||||
}
|
||||
}
|
||||
|
||||
return base.ReadJson( reader, objectType, existingValue, serializer );
|
||||
}
|
||||
}
|
||||
|
||||
public static partial class JsonExtensions
|
||||
{
|
||||
public static JsonReader MoveToContentAndAssert( this JsonReader reader )
|
||||
{
|
||||
if( reader == null )
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
if( reader.TokenType == JsonToken.None ) // Skip past beginning of stream.
|
||||
{
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
while( reader.TokenType == JsonToken.Comment ) // Skip past comments.
|
||||
{
|
||||
reader.ReadAndAssert();
|
||||
}
|
||||
|
||||
return reader;
|
||||
}
|
||||
|
||||
public static JsonReader ReadAndAssert( this JsonReader reader )
|
||||
{
|
||||
if( reader == null )
|
||||
{
|
||||
throw new ArgumentNullException();
|
||||
}
|
||||
|
||||
if( !reader.Read() )
|
||||
{
|
||||
throw new JsonReaderException( "Unexpected end of JSON stream." );
|
||||
}
|
||||
|
||||
return reader;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue