Title: node-minecraft-protocol: brand and Client Information are sent only on the first configuration entry — vanilla re-sends them after every server transfer
Body:
What happens
enterConfigState gates brand + settings behind a one-shot flag:
// Brand then Client Information are sent once per connection, on the first entry
// into configuration; re-entering configuration from play sends nothing else.
if (!sentClientInformation) { ... }
With Velocity modern transfers (play → configuration re-entry → play), every server the client is transferred to sees a client with no brand and no Client Information. The vanilla client sends both on every configuration phase (each world gets them again). Some servers validate the brand per world; without it the client is treated as non-vanilla (we were console-kicked "Cheating" on a network whose game servers check, while its lobbies didn't).
Fix (field-verified)
Send both on every entry into configuration (the original Hypixel ordering constraint is preserved — they still go out immediately on entry):
sentClientInformation = true
client.write('custom_payload', { channel: 'minecraft:brand', data: ... })
client.write('settings', { ... })
Fresh-account survival in a previously-kicking game world went from <60s to indefinite after this plus the pong-order and chunk-stall fixes. Single change alone is necessary but not sufficient; the three together stopped the kicks.
Patch: patches/nmp-brand-settings-every-config.patch (23 lines, src/client/play.js).
Patch
diff --git a/packages/minecraft-protocol/src/client/play.js b/packages/minecraft-protocol/src/client/play.js
index d3e3fd0..9be98ee 100644
--- a/packages/minecraft-protocol/src/client/play.js
+++ b/packages/minecraft-protocol/src/client/play.js
@@ -56,29 +56,28 @@ module.exports = function (client, options) {
client.write('configuration_acknowledged', {})
}
client.state = states.CONFIGURATION
- // Brand then Client Information are sent once per connection, on the first entry
- // into configuration; re-entering configuration from play sends nothing else. Some
- // servers (e.g. Hypixel) close the socket unless Client Information arrives before
- // they send finish_configuration
- if (!sentClientInformation) {
- sentClientInformation = true
- client.write('custom_payload', {
- channel: 'minecraft:brand',
- data: client.serializer.proto.createPacketBuffer('string', options.brand ?? 'vanilla')
- })
- const clientSettings = options.clientSettings || {}
- client.write('settings', {
- locale: clientSettings.locale ?? 'en_us',
- viewDistance: clientSettings.viewDistance ?? 12,
- chatFlags: clientSettings.chatFlags ?? 0,
- chatColors: clientSettings.chatColors ?? true,
- skinParts: clientSettings.skinParts ?? 127,
- mainHand: clientSettings.mainHand ?? 1,
- enableTextFiltering: clientSettings.enableTextFiltering ?? false,
- enableServerListing: clientSettings.enableServerListing ?? true,
- particleStatus: clientSettings.particleStatus ?? 'all'
- })
- }
+ // Brand then Client Information go out on EVERY entry into configuration, including
+ // re-entry after a server transfer: the vanilla client re-sends both for each world,
+ // and servers that validate the brand per world never see it again otherwise.
+ // Hypixel closes the socket unless Client Information arrives before they send
+ // finish_configuration, hence the send right here rather than later.
+ sentClientInformation = true
+ client.write('custom_payload', {
+ channel: 'minecraft:brand',
+ data: client.serializer.proto.createPacketBuffer('string', options.brand ?? 'vanilla')
+ })
+ const clientSettings = options.clientSettings || {}
+ client.write('settings', {
+ locale: clientSettings.locale ?? 'en_us',
+ viewDistance: clientSettings.viewDistance ?? 12,
+ chatFlags: clientSettings.chatFlags ?? 0,
+ chatColors: clientSettings.chatColors ?? true,
+ skinParts: clientSettings.skinParts ?? 127,
+ mainHand: clientSettings.mainHand ?? 1,
+ enableTextFiltering: clientSettings.enableTextFiltering ?? false,
+ enableServerListing: clientSettings.enableServerListing ?? true,
+ particleStatus: clientSettings.particleStatus ?? 'all'
+ })
// The server omits the registry entries of every pack in the reply, so a pack may
// only be listed when its data is available locally
client.once('select_known_packs', (packet) => {
Title: node-minecraft-protocol: brand and Client Information are sent only on the first configuration entry — vanilla re-sends them after every server transfer
Body:
What happens
enterConfigStategates brand + settings behind a one-shot flag:With Velocity modern transfers (play → configuration re-entry → play), every server the client is transferred to sees a client with no brand and no Client Information. The vanilla client sends both on every configuration phase (each world gets them again). Some servers validate the brand per world; without it the client is treated as non-vanilla (we were console-kicked "Cheating" on a network whose game servers check, while its lobbies didn't).
Fix (field-verified)
Send both on every entry into configuration (the original Hypixel ordering constraint is preserved — they still go out immediately on entry):
Fresh-account survival in a previously-kicking game world went from <60s to indefinite after this plus the pong-order and chunk-stall fixes. Single change alone is necessary but not sufficient; the three together stopped the kicks.
Patch:
patches/nmp-brand-settings-every-config.patch(23 lines,src/client/play.js).Patch