docs.unity3d.com
Search Results for

    Show / Hide Table of Contents

    Prediction smoothing

    Prediction errors can occur for a number of reasons: variations in logic between clients and the server, packet drops, quantization errors, and so on. For predicted entities the net effect is that when rolling back and resimulating from the latest available snapshot, there can be a significant difference between the recomputed values and the originally predicted values. The GhostPredictionSmoothingSystem system provides a way of reconciling and reducing these errors over time to make the transitions between the two states smoother.

    For each component, you can configure how to manage these errors by registering a Smoothing Action Function on the GhostPredictionSmoothing singleton which smooths the error out over time.

        public delegate void SmoothingActionDelegate(void* currentData, void* previousData, void* userData);
        //pass null as user data
        GhostPredictionSmoothing.RegisterSmoothingAction<Translation>(EntityManager, MySmoothingAction);
        //will pass as user data a pointer to a MySmoothingActionParams chunk component
        GhostPredictionSmoothing.RegisterSmoothingAction<Translation, MySmoothingActionParams>(EntityManager, DefaultTranslateSmoothingAction.Action);
    

    The user data must be a chunk-component present in the entity. A default implementation for smoothing out any translation prediction errors is provided by the package.

    world.GetSingleton<GhostPredictionSmoothing>().RegisterSmootingAction<Translation>(EntityManager, CustomSmoothing.Action);
    
    [BurstCompile]
    public unsafe class CustomSmoothing
    {
        public static readonly PortableFunctionPointer<GhostPredictionSmoothing.SmoothingActionDelegate>
            Action =
                new PortableFunctionPointer<GhostPredictionSmoothing.SmoothingActionDelegate>(SmoothingAction);
    
        [BurstCompile(DisableDirectCall = true)]
        private static void SmoothingAction(void* currentData, void* previousData, void* userData)
        {
            ref var trans = ref UnsafeUtility.AsRef<Translation>(currentData);
            ref var backup = ref UnsafeUtility.AsRef<Translation>(previousData);
    
            var dist = math.distance(trans.Value, backup.Value);
            //UnityEngine.Debug.Log($"Custom smoothing, diff {trans.Value - backup.Value}, dist {dist}");
            if (dist > 0)
                trans.Value = backup.Value + (trans.Value - backup.Value) / dist;
        }
    }
    

    Smoothing frequency

    The PredictionSmoothingSystem doesn't correct prediction errors every single frame (at the rendering frame rate). The registered corrective actions are invoked only when a client reconciles its state because a new snapshot (containing predicted ghosts) is received from the server.

    During the resimulation, when the current server tick equals the last predicted full tick, the smoothing corrections are applied to all ghosts.

    Note

    The only requirement for the smoothing action to run is that the client rewinds and resimulates its state (which requires predicted ghost state updates). The correction applied to the individual entities is not correlated to the fact that a state update has been received for them in the last packet.

    Limitations and known issues

    • The quality of the correction depends on the frequency with which predicted ghost data is received.
      • Jittery connections and lag spikes can affect the prediction correction.
      • Large numbers of replicated ghosts (either predicted or replicated), or in general predicted ghost updates being received for a certain amount of time, also affect the frequency of the correction.
    • Structural changes (such as adding or removing a component on a predicted ghost entity) may prevent corrections from being applied. Entities that have changed chunks or that are still in the same chunk but have been moved since the last prediction history backup will not have their prediction smoothing applied.
    • Because prediction smoothing is based on function pointer callbacks, there may not be enough context or flexibility inside the smoothing function implementation to apply the logic you may need. The Smoothing Action delegates are supposed to be simple and stateless.

    Additional resources

    • Introduction to prediction
    • Managing latency with prediction
    In This Article
    Back to top
    Copyright © 2025 Unity Technologies — Trademarks and terms of use
    • Legal
    • Privacy Policy
    • Cookie Policy
    • Do Not Sell or Share My Personal Information
    • Your Privacy Choices (Cookie Settings)