Skip to content

AgentSetAppearance sends 218 VisualParams (viewers send 253) — positional mismatch deforms the avatar body on OpenSim #176

Description

@sharpdaddy59

Summary

AppearanceManager.MakeAppearancePacket() hard-caps the VisualParam block
count at 218 (251 with a Physics wearable):

// LibreMetaverse/Appearance/AppearanceManager.cs (master @ 9455bdb, line 2490)
var nrParams = wearingPhysics ? 251 : 218;
set.VisualParam = new AgentSetAppearancePacket.VisualParamBlock[nrParams];

Modern viewers (tested against Firestorm) send 253 VisualParam blocks.
The array is positional — the receiver maps values onto its ordered param
table by index — so a library-driven client that sets its appearance on an
OpenSim region deforms the avatar: the first ~23 values line up, then the
membership of the library's VisualParams.Params enumeration diverges from
the viewer's ordering and every subsequent value lands on the wrong
slider
(torso/leg/height params get unrelated values → grossly deformed,
"squashed" body). OpenSim persists the received array, so the corruption
also survives to subsequent sessions.

Reproduction

  1. Dress an avatar with a viewer (Firestorm) on an OpenSim grid
    (0.9.3.0 standalone in our case) and log out. The grid's avatars.db
    VisualParams row now holds 253 comma-separated values.
  2. Log the same avatar in with a LibreMetaverse 3.1.3 client with
    Settings.Agent.SendAppearance enabled (default) and let the CSB
    pipeline run to completion (all wearables download, bake succeeds,
    AppearanceSet fires with Success = true).
  3. Observe in any viewer: the avatar's body is deformed. Inspect the
    persisted VisualParams row: now 218 values.

Direct comparison of the persisted arrays (same avatar, same wearables):

viewer  count=253: ... 63, 165, 88, 132,   0, 136,  81,  85, 103, 136 ...
                                     ^ index 23
library count=218: ... 63, 165, 88,   0, 132,   0,  63,  63,   0,   0 ...

Identical through index 22, then the library's sequence contains an entry
the viewer's ordering doesn't have (or vice versa) and everything shifts.
The values the library computes are correct — the height-related params
it looks up by ID for AgentData.Size produce the right avatar height —
only the positional serialization is wrong.

Expected

The VisualParam array should match the current viewer wire format: 253
entries, same param membership and ordering, so index N means the same
slider to every receiver.

Suggested fix

Bring VisualParams.Params (and the nrParams cap) up to date with the
current avatar_lad param set used by SL/Firestorm-era viewers (253 params,
Bakes-on-Mesh era), and derive the block count from the table rather than
the hardcoded 218/251. The special-casing on wearingPhysics suggests the
table already contains more params than are sent — the cap, not the table,
may be the immediate problem, but membership/order needs to match too
(the divergence starts at index ~23, well before the physics params).

Workaround we're using

Send appearance packets ourselves: let the CSB pipeline bake, then rebuild
the packet via the (public) MakeAppearancePacket() and replace
pkt.VisualParam with the 253-value array the grid has persisted from a
viewer session before sending. This renders correctly everywhere and
round-trips through OpenSim persistence.

Happy to provide logs or test on a branch.


Environment: LibreMetaverse 3.1.3 (NuGet, repo commit 70877a6), .NET 10,
OpenSim 0.9.3.0 standalone, observed with Firestorm viewers.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions