Netcode 1.1.0-exp.1 Prediction Smoothing Action backup / previous values can be invalid.

Hi,
I have noticed that invalid values can sometimes be applied to the previous/backup value in a Prediction Smoothing Action. To create a simple reproduction, I added the following system to the Asteroids Sample:

using Unity.Burst;
using Unity.Entities;
using Unity.NetCode;
using Unity.Transforms;
using System;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Mathematics;

namespace Samples.Asteroids.Client.Systems
{
    [BurstCompile]
    [WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]
    [CreateAfter(typeof(GhostPredictionSmoothingSystem))]
    public partial struct RegisterPredictionSmoothingSystem : ISystem
    {
        public void OnCreate(ref SystemState state)
        {
            // ReSharper disable once Unity.Entities.SingletonMustBeRequested
            var ghostPredictionSmoothing = SystemAPI.GetSingleton<GhostPredictionSmoothing>();

            ghostPredictionSmoothing.RegisterSmoothingAction<LocalTransform>(state.EntityManager,
                MyTranslationSmoothingAction.Action);
        }
    }
   
    /// <summary>
    /// The default prediction error <see cref="SmoothingAction"/> function for the <see cref="Translation"/> component.
    /// Supports the user data that lets you customize the clamping and snapping of the translation component (any time the translation prediction error is too large).
    /// </summary>
    [BurstCompile]
    public unsafe struct MyTranslationSmoothingAction
    {
        /// <summary>
        /// The default value for the <see cref="DefaultSmoothingActionUserParams"/> if the no user data is passed to the function.
        /// Position is corrected if the prediction error is at least 1 unit (usually mt) and less than 10 unit (usually mt)
        /// </summary>
        public sealed class DefaultStaticUserParams
        {
            internal static readonly SharedStatic<float> maxDist =
                SharedStatic<float>.GetOrCreate<DefaultStaticUserParams, MaxDistKey>();

            internal static readonly SharedStatic<float> delta =
                SharedStatic<float>.GetOrCreate<DefaultStaticUserParams, DeltaKey>();

            static DefaultStaticUserParams()
            {
                maxDist.Data = 10;
                delta.Data = 1;
            }

            class MaxDistKey
            {
            }

            class DeltaKey
            {
            }
        }

        /// <summary>
        /// Return a the burst compatible function pointer that can be used to register the smoothing action to the
        /// <see cref="GhostPredictionSmoothing"/> singleton.
        /// </summary>
        public static readonly PortableFunctionPointer<GhostPredictionSmoothing.SmoothingActionDelegate> Action =
            new PortableFunctionPointer<GhostPredictionSmoothing.SmoothingActionDelegate>(SmoothingAction);

        [BurstCompile(DisableDirectCall = true)]
        [AOT.MonoPInvokeCallback(typeof(GhostPredictionSmoothing.SmoothingActionDelegate))]
        private static void SmoothingAction(IntPtr currentData, IntPtr previousData, IntPtr usrData)
        {
            ref var trans = ref UnsafeUtility.AsRef<LocalTransform>((void*) currentData);
            ref var backup = ref UnsafeUtility.AsRef<LocalTransform>((void*) previousData);

            float maxDist = DefaultStaticUserParams.maxDist.Data;
            float delta = DefaultStaticUserParams.delta.Data;

            if (usrData.ToPointer() != null)
            {
                ref var userParam = ref UnsafeUtility.AsRef<DefaultSmoothingActionUserParams>(usrData.ToPointer());
                maxDist = userParam.maxDist;
                delta = userParam.delta;
            }

            var dist = math.distance(trans.Position, backup.Position);
           
           
            UnityEngine.Debug.Log($"cp: {trans.Position} bp: {backup.Position}");
           
            if (dist < maxDist && dist > delta && dist > 0)
            {
                trans.Position = backup.Position + (trans.Position - backup.Position) * delta / dist;
            }
        }
    }
}

The MyTranslationSmoothingAction is a copy of the DefaultTranslationSmoothingAction with a debug added. The debug statement will sometimes generate the following result:

Erroneous NaN and near zero values are sometimes loaded into the backup / previous LocalTransform.

Hey! mmm this is indeed interesting. We will check this with high priority! Super thanks for reporting this.
Would you mind to open a case for it so we can track the issue properly?

Hi,

I have filed a bug report for this issue: CASE IN-58319.

Thank you.

1 Like

Was this fixed for you with the [1.1.0-pre.3]?
I am having the same issue on [1.0.15] (cherry picking the fixes did not seem to solve it).

IT should have been fixed in 1.1. I will double check just in case.

1 Like