Skip to content

Feature: Physics Tracking and State Packet Batching

Tsu edited this page Jun 9, 2026 · 2 revisions

This feature set optimizes entity tracking updates and state-change packet emission in PhysicsManager.

Where It Lives

Main patch:

  • patches/VintagestoryLib/Vintagestory.Server/PhysicsManager.cs.patch

No-Client Fast Path in Tracking

UpdateTrackedEntityState(...) exits early when there are no clients:

if (clients.Count == 0)
{
    entity.IsTracked = 0;
    if (!(entity is EntityPlayer))
    {
        CompletePositionUpdate(entity);
    }
    entity.NearestPlayerDistance = float.PositiveInfinity;
    if (!entity.AlwaysActive && entity.State == EnumEntityState.Active)
    {
        entity.State = EnumEntityState.Inactive;
        return true;
    }
    return false;
}

This avoids unnecessary distance/tracking loops when nobody is connected.

Staff Visibility Filter During Tracking

Tracked-entity sets can skip hidden entities per client:

if (StratumStaffCommandState.ShouldHideEntityFromClient(item, client))
{
    continue;
}

Equivalent filtering is applied across threaded tracked-entity lists.

State Change Packet Caching and Batching

SendTrackedEntitiesStateChanges() reuses buffers and caches generated packets:

List<Packet_Entity> entityPackets = stateChangeEntityPackets;
Dictionary<long, Packet_Entity> entityPacketCache = stateChangeEntityPacketCache;
Dictionary<long, PreparedStateChangePacket> playerDataPacketCache = stateChangePlayerDataPacketCache;
Dictionary<long, AnimationPacket> animationPacketCache = stateChangeAnimationPacketCache;

Full entity packets are built once per entity and reused across clients in the same pass:

if (!entityPacketCache.TryGetValue(entityIdForPacket, out Packet_Entity entityPacket))
{
    fastMemoryStream.Reset();
    entityPacket = ServerPackets.GetEntityPacket(entity, fastMemoryStream, writer);
    entityPacketCache[entityIdForPacket] = entityPacket;
}

Player-data packets are prepared once and sent as prepared bytes for multiplayer clients:

byte[] packetBytes = client.Socket.PreparePacketForSending(stateChangeSerializedPacket, server.Config.CompressPackets, out bool compressed);
preparedPacket = new PreparedStateChangePacket(packetBytes, compressed);
playerDataPacketCache[entityId] = preparedPacket;
server.SendPreparedPacket(client, preparedPacket.PacketBytes, preparedPacket.Compressed);

Timing Buckets

The patch records measured ticks for detailed packet paths:

  • physics.sendStatePlayerPackets
  • physics.sendStateFullEntityBuild
  • physics.sendStateFullEntitySend
  • physics.sendStateAnimations
  • physics.sendStateDespawns

It also records section timings such as:

  • physics.updateTrackedLists
  • physics.sendStateChanges
  • physics.sendSpawns
  • physics.manager

Debug Logging

The old periodic PhysicsManager tickables=... notification is disabled. It was useful while tuning the parallel threshold, but it made normal server logs noisy. Use /stratum timings and /stratum performance for current physics and chunk pressure checks.

Source of Truth

  • patches/VintagestoryLib/Vintagestory.Server/PhysicsManager.cs.patch
  • VintagestoryLib/Vintagestory.Server/PhysicsManager.cs

Clone this wiki locally