Skip to content

Expose and forward decorated signed player chat through the Velocity API#1846

Draft
airgalaxie wants to merge 5 commits into
PaperMC:dev/4.0.0from
airgalaxie:feature/signed-player-chat-api
Draft

Expose and forward decorated signed player chat through the Velocity API#1846
airgalaxie wants to merge 5 commits into
PaperMC:dev/4.0.0from
airgalaxie:feature/signed-player-chat-api

Conversation

@airgalaxie

Copy link
Copy Markdown

Summary

Velocity parses and forwards modern Minecraft signed player chat internally,
but the public PlayerChatEvent API currently exposes only the player and
the plaintext message.

This pull request exposes the original protocol-level player chat metadata
through the public API and adds a general Velocity-managed path for delivering
server-decorated player chat to selected proxy players.

The implementation is not tied to a specific chat plugin. It provides a
general API foundation that plugins can use without accessing internal packet
classes or implementing version-specific Minecraft protocol handling.

Motivation

Modern Minecraft player chat is no longer just a plaintext string. Depending
on the protocol generation, it includes:

  • sender identity
  • original message body
  • signed state
  • signature
  • timestamp
  • salt
  • keyed or session identity
  • last-seen and message-chain metadata

Velocity already processes much of this information internally, but plugins
cannot currently inspect or use it through PlayerChatEvent.

Command execution already exposes signed invocation state. Normal player chat
currently remains signature-blind at the public API boundary.

Changes

This pull request:

  • adds an immutable public representation of the original player chat message
  • distinguishes legacy, keyed-signed, and session-signed chat
  • exposes only validation states that Velocity actually knows
  • preserves backward compatibility with the existing PlayerChatEvent API
  • adds a general decorated player-chat result with selected recipients
  • keeps the original signed body separate from server-controlled decoration
  • adds versioned clientbound player-chat packet encoding
  • suppresses normal backend forwarding only after successful Velocity delivery
  • does not silently fall back to system chat

Protocol support

  • Legacy chat: decorated legacy output without signature claims
  • Minecraft 1.19–1.19.2 keyed signed chat:
    metadata is exposed, but decorated signature-preserving emission is not
    currently supported
  • Minecraft 1.19.3–1.21.4 session chat:
    versioned decorated player-chat emission
  • Minecraft 1.21.5 and later supported protocols:
    versioned emission including the protocol global index where required

Validation and limitations

Signed does not automatically mean validated.

The API distinguishes between metadata being present, structurally complete,
session-associated, and actually validated.

This change does not currently claim:

  • cryptographic message-signature validation
  • full message-chain validation
  • complete per-recipient chain reconstruction

Unsupported protocol paths are reported explicitly. No silent system-chat
fallback is used.

Compatibility

Existing methods and constructors remain available:

  • PlayerChatEvent#getPlayer()
  • PlayerChatEvent#getMessage()
  • PlayerChatEvent#getResult()
  • PlayerChatEvent#setResult(...)

No internal or version-specific packet classes are exposed through
velocity-api.

Tests

The following verification completed successfully:

./gradlew :velocity-api:check :velocity-proxy:check
./gradlew check shadowJar

Supersedes #1845, which targeted the previous development branch.

Velocity already parses and validates signed Minecraft player chat internally, but PlayerChatEvent currently exposes only the player and plaintext message to plugins.

Carry the original signed-message metadata across the public API boundary so ecosystem plugins can inspect modern Minecraft signed chat without depending on internal packet classes.

This change is backward compatible and does not alter validation, forwarding, cancellation or rewrite behavior.
Make decorated player-chat forwarding atomic by preflighting every requested recipient and packet representation before any network write. Backend forwarding is now suppressed only when the proxy fully takes over delivery or when an empty recipient list intentionally delivers to nobody.

Model clientbound chat-type parameters separately from the full decorated content, remove the implicit username sender binding, and keep empty recipient lists as an explicit routing result. Update tests with neutral data for atomic fallback, null delivery, final ChatResult behavior, defensive recipient copies, and explicit decoration parameters.
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.

1 participant