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

Unity Keyframe bug, different size in editor and app #368

Open
songqian1130 opened this issue Feb 7, 2025 · 1 comment
Open

Unity Keyframe bug, different size in editor and app #368

songqian1130 opened this issue Feb 7, 2025 · 1 comment

Comments

@songqian1130
Copy link

songqian1130 commented Feb 7, 2025

public T[]? DangerousReadUnmanagedArray<T>()
{
  int length;
  if (!this.TryReadCollectionHeader(out length))
    return (T[]) null;
  if (length == 0)
    return Array.Empty<T>();
  int num = length * Unsafe.SizeOf<T>();
  ref byte local = ref this.GetSpanReference(num);
  T[] array = MemoryMarshalEx.AllocateUninitializedArray<T>(length);
  Unsafe.CopyBlockUnaligned(ref Unsafe.As<T, byte>(ref MemoryMarshalEx.GetArrayDataReference<T>(array)), ref local, (uint) num);
  this.Advance(num);
  return array;
}

in release:

keyframe:

	private float m_Time;

	private float m_Value;

	private float m_InTangent;

	private float m_OutTangent;

       //private int m_TangentMode; only in editor

	private int m_WeightedMode;

	private float m_InWeight;

	private float m_OutWeight;

here SizeOf will change, because m_TangentMode doesn't exist in release.
by the way, should I also consider the struct layout in different platform? will this also cause deserialize fail?

@songqian1130
Copy link
Author

songqian1130 commented Feb 7, 2025

[Preserve]
internal sealed class AnimationCurveFormatter : MemoryPackFormatter<AnimationCurve>
{
    public void WriteArray<T, TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, T?[]? value) where TBufferWriter : class, IBufferWriter<byte>
    {
        if (value == null)
        {
            writer.WriteNullCollectionHeader();
        }
        else
        {
            IMemoryPackFormatter<T> formatter = writer.GetFormatter<T>();
            writer.WriteCollectionHeader(value.Length);
            for (int index = 0; index < value.Length; ++index)
                formatter.Serialize<TBufferWriter>(ref writer, ref value[index]);
        }
    }
    
    public void ReadArray<T>(ref MemoryPackReader reader, ref T?[]? value)
    {
        int length;
        if (!reader.TryReadCollectionHeader(out length))
            value = (T[]) null;
        else if (length == 0)
        {
            value = Array.Empty<T>();
        }
        else
        {
            if (value == null || value.Length != length)
                value = new T[length];
            IMemoryPackFormatter<T> formatter = reader.GetFormatter<T>();
            for (int index = 0; index < length; ++index)
                formatter.Deserialize(ref reader, ref value[index]);
        }
    }
    
    [Preserve]
    public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, ref AnimationCurve? value)
    {
        if (value == null)
        {
            writer.WriteNullObjectHeader();
            return;
        }

        writer.WriteUnmanagedWithObjectHeader(3, value.@preWrapMode, value.@postWrapMode);
        WriteArray(ref writer, value.@keys);
    }

    [Preserve]
    public override void Deserialize(ref MemoryPackReader reader, ref AnimationCurve? value)
    {
        if (!reader.TryReadObjectHeader(out var count))
        {
            value = null;
            return;
        }

        if (count != 3) MemoryPackSerializationException.ThrowInvalidPropertyCount(3, count);

        reader.ReadUnmanaged(out WrapMode preWrapMode, out WrapMode postWrapMode);
        Keyframe[]? keys = null;
        ReadArray<global::UnityEngine.Keyframe>(ref reader, ref keys);

        if (value == null)
        {
            value = new AnimationCurve();
        }

        value.preWrapMode = preWrapMode;
        value.postWrapMode = postWrapMode;
        value.keys = keys;
    }
}

[Preserve]
internal sealed class KeyframeFormatter : MemoryPackFormatter<Keyframe>
{
    [Preserve]
    public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, ref Keyframe value)
    {
        writer.WriteUnmanaged(value.time, value.value, value.inTangent, value.outTangent, value.weightedMode, value.inWeight, value.outWeight);
    }

    [Preserve]
    public override void Deserialize(ref MemoryPackReader reader, ref Keyframe value)
    {
        float ___time;
        float ___value;
        float ___inTangent;
        float ___outTangent;
        int ___weightedMode;
        float ___inWeight;
        float ___outWeight;
        
        reader.ReadUnmanaged(out ___time, out ___value, out ___inTangent, out ___outTangent, out ___weightedMode, out ___inWeight, out ___outWeight);
        
        value.time = ___time;
        value.value = ___value;
        value.inTangent = ___inTangent;
        value.outTangent = ___outTangent;
        value.weightedMode = (WeightedMode)___weightedMode;
        value.inWeight = ___inWeight;
        value.outWeight = ___outWeight;
    }
}

I just change this code. then it will be ok. however, I'm not really sure that some custom struct need add the [StructLayout(LayoutKind.Sequential, Pack = 8)] to force my custom struct to be the same in different platforms.
Should I add this attribute?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant