Skip to content

Send transformed players to the open-source client in its extended layout - #997

Merged
sven-n merged 2 commits into
MUnique:masterfrom
alandarev:fix/transformed-players-extended-layout
Sep 28, 2026
Merged

sven-n merged 2 commits into
MUnique:masterfrom
alandarev:fix/transformed-players-extended-layout

Conversation

@alandarev

@alandarev alandarev commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #996.

What

Players wearing a transformation ring were invisible to the open-source client (106.3): the
extended appearance data (27 bytes) was written into the 18-byte appearance field of
AddTransformedCharactersToScope, which threw, so nothing was sent and the rest of the scope
update was lost too (details in #996).

  • Network/Packets: new AddTransformedCharacterToScopeExtended (C2 45) with one character per
    packet, followed by the appearance data of the serializer and the effect ids, like
    AddCharacterToScopeExtended does for C2 12. The fields match the client's
    PCREATE_TRANSFORM_EXTENDED. Structs, ConnectionExtensions, generated tests and packet docs
    are regenerated from the XML.
  • GameServer/RemoteView/World: NewPlayersInScopePlugIn.SendTransformedCharacterAsync is now
    protected virtual (moved before the private method for StyleCop), and
    NewPlayersInScopeExtendedPlugIn overrides it with the new packet. Older clients keep the
    existing packet.
  • A second commit writes the shop/guild list additions in SendCharactersAsync as two statements;
    Codacy flags the moved lines with S1121 otherwise.

Client side

The client also needs sven-n/MuMain#654: it required every C2 45 entry to have room for 16
buffs, so it dropped the entries this server sends. With only one of the two fixes, transformed
players stay invisible.

Testing

  • tests/MUnique.OpenMU.Tests/NewPlayersInScopeRemoteViewTests.cs: the extended layout (read
    back through the packet struct, and as raw bytes at the client's offsets with and without the
    spawn flag and with effects), the standard layout for older clients, and a normal player after a
    transformed one in the same update. Four of the five fail on master with the exception above.
  • MUnique.OpenMU.Network.Packets.Tests 608/608, MUnique.OpenMU.Tests 1068/1068; the Docker
    image builds without warnings in the changed files.
  • By hand: a character with the Elite Skeleton Transformation Ring next to a second character on
    the open-source client (with the client fix): the skeleton is shown with the character's name,
    and the server logs no errors.
  • Codacy: one remaining finding, MD047 (no trailing newline) in the generated
    docs/Packets/C2-45-AddTransformedCharacterToScopeExtended_by-server.md. The markdown generator
    writes every packet document that way.

Written with AI assistance and tested by hand, per CONTRIBUTING.

… extended layout

The open-source client (106.3) gets its appearance data from
AppearanceSerializerExtended, which needs 27 bytes. Transformed players
were still sent through AddTransformedCharactersToScope, whose appearance
field holds 18 bytes, so WriteAppearanceData threw: nothing was sent, and
the exception also dropped every player after it in the same scope update,
with their shops and guild info. Players wearing a transformation ring
were invisible to that client.

- AddTransformedCharacterToScopeExtended (C2 45): one character, followed
  by the appearance data of the serializer and the effects, as the
  client's PCREATE_TRANSFORM_EXTENDED reads them.
- NewPlayersInScopePlugIn.SendTransformedCharacterAsync is protected
  virtual; NewPlayersInScopeExtendedPlugIn overrides it.
- Tests for both layouts and for players following a transformed one.
…tements

Codacy (SonarC# S1121) flags the assignment inside the expression.

sven-n commented Sep 28, 2026

Copy link
Copy Markdown
Member

Reviewed and tested. Looks good to merge.

Verification (PR head merged locally onto current master, which merges cleanly):

  • MUnique.OpenMU.Tests: 1100/1100 passed, including the 5 new NewPlayersInScopeRemoteViewTests.
  • MUnique.OpenMU.Network.Packets.Tests: 608/608 passed.
  • The build left no changes in the generated files, and no new warnings in the changed files.

Layout check against the client (PCREATE_TRANSFORM_EXTENDED in MuMain WSclient.h): header and count take 5 bytes. Key, position, skin, name, target and path take 19 bytes, so the appearance data starts at offset 24, as in the new packet definition. Class, flags and the 25 equipment bytes are the 27 bytes of AppearanceSerializerExtended.NeededSpace, so the buff count lands at offset 51, which the raw-byte test checks. The spawn bit in KeyH matches the client's Key >> 15.

Code notes:

  • The override follows SendCharacterAsync of the extended plug-in. Indexing VisibleEffects directly, instead of copying it to a stackalloc first, is safe because the getter returns a snapshot list taken under the lock.
  • Making SendTransformedCharacterAsync protected virtual means older clients keep the existing packet unchanged. That scope is right.
  • The failing MUnique.OpenMU Azure check fails instantly on other PRs too (e.g. Docs: item drops configuration page #998), so it's unrelated to this change. The MD047 finding comes from the markdown generator and is fine to leave.

As the description says, transformed players only show up once sven-n/MuMain#654 is also merged.


Generated by Claude Code

@sven-n
sven-n merged commit 0db6db1 into MUnique:master Sep 28, 2026
1 of 2 checks passed
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

Successfully merging this pull request may close these issues.

Transformed players are invisible to the open-source client (Target span too small in NewPlayersInScopePlugIn)

2 participants