11/**
22 * Velocity proxy support for Minecraft 1.20.2+ configuration phase
33 *
4- * This plugin manages the configuration phase introduced in Minecraft 1.20.2
5- * and extended in 1.21+, which is required for proper server transfers via
6- * Velocity proxy .
4+ * This plugin manages the re- configuration phase that occurs during
5+ * server transfers via Velocity proxy. It does NOT interfere with the
6+ * initial login configuration (handled by node-minecraft-protocol) .
77 *
8- * During the configuration phase :
8+ * During re- configuration:
99 * - Gameplay packets (movement, physics) are not allowed
10- * - Only configuration packets should be sent
11- * - Resource packs must be handled correctly
10+ * - Resource packs must be accepted for the transfer to complete
1211 *
1312 * Issue: https://github.com/PrismarineJS/mineflayer/issues/3764
1413 */
@@ -18,7 +17,10 @@ module.exports = inject
1817function inject ( bot ) {
1918 // Track whether we're in configuration phase
2019 bot . inConfigurationPhase = false
21- let configurationFinished = false
20+
21+ // Only activate after the first spawn -- the initial login configuration
22+ // is already handled by node-minecraft-protocol and we must not interfere.
23+ let hasInitiallySpawned = false
2224
2325 // Resource pack response codes
2426 const TEXTURE_PACK_RESULTS = {
@@ -29,13 +31,13 @@ function inject (bot) {
2931 }
3032
3133 /**
32- * Enter configuration phase
34+ * Enter configuration phase (only for re-entry, not initial login)
3335 */
3436 function enterConfigurationPhase ( ) {
3537 if ( bot . inConfigurationPhase ) return
38+ if ( ! hasInitiallySpawned ) return
3639
3740 bot . inConfigurationPhase = true
38- configurationFinished = false
3941
4042 // Disable physics during configuration to prevent movement packets
4143 if ( bot . physicsEnabled !== undefined ) {
@@ -54,7 +56,7 @@ function inject (bot) {
5456
5557 bot . inConfigurationPhase = false
5658
57- // Re-enable physics after configuration
59+ // Re-enable physics after a short delay to let the server finish setup
5860 setTimeout ( ( ) => {
5961 if ( bot . _physicsWasEnabled && ! bot . _ended ) {
6062 bot . physicsEnabled = true
@@ -65,52 +67,39 @@ function inject (bot) {
6567 bot . emit ( 'configurationPhase' , 'end' )
6668 }
6769
70+ // Mark initial spawn complete -- after this, configuration phase events
71+ // are treated as Velocity re-configuration (server transfers).
72+ bot . once ( 'spawn' , ( ) => {
73+ hasInitiallySpawned = true
74+ } )
75+
6876 // === CONFIGURATION PHASE DETECTION ===
6977
70- // Method 1: start_configuration event (1.20.2+)
78+ // start_configuration is sent by the server to re-enter config state (1.20.2+)
7179 bot . _client . on ( 'start_configuration' , ( ) => {
7280 enterConfigurationPhase ( )
7381 } )
7482
75- // Method 2: select_known_packs event (1.21+)
76- bot . _client . on ( 'select_known_packs' , ( packet ) => {
77- enterConfigurationPhase ( )
78- // Note: No response needed for select_known_packs
79- } )
80-
81- // Method 3: registry_data event (1.20.2+)
82- bot . _client . on ( 'registry_data' , ( packet ) => {
83- // Only enter if not already in configuration phase
84- // (registry_data can be sent multiple times)
85- if ( ! bot . inConfigurationPhase ) {
86- enterConfigurationPhase ( )
87- }
88- } )
89-
90- // Method 4: transfer event (1.20.5+)
91- bot . _client . on ( 'transfer' , ( packet ) => {
83+ // transfer event (1.20.5+) -- server is transferring us
84+ bot . _client . on ( 'transfer' , ( ) => {
9285 enterConfigurationPhase ( )
9386 } )
9487
9588 // === AUTOMATIC RESOURCE PACK ACCEPTANCE ===
9689
97- /**
98- * Automatically accept resource packs during configuration phase
99- * This is required for Velocity transfers to complete successfully
100- */
90+ // Automatically accept resource packs during configuration phase.
91+ // This is required for Velocity transfers to complete -- the server
92+ // waits for SUCCESSFULLY_LOADED before sending finish_configuration.
10193
10294 // Handle add_resource_pack (1.20.3+)
10395 bot . _client . prependListener ( 'add_resource_pack' , ( data ) => {
10496 if ( ! bot . inConfigurationPhase ) return
10597
106- // Send ACCEPTED immediately
10798 bot . _client . write ( 'resource_pack_receive' , {
10899 uuid : data . uuid ,
109100 result : TEXTURE_PACK_RESULTS . ACCEPTED
110101 } )
111102
112- // Send SUCCESSFULLY_LOADED immediately
113- // Server needs this before sending finish_configuration
114103 bot . _client . write ( 'resource_pack_receive' , {
115104 uuid : data . uuid ,
116105 result : TEXTURE_PACK_RESULTS . SUCCESSFULLY_LOADED
@@ -120,52 +109,35 @@ function inject (bot) {
120109 // Handle resource_pack_send (older versions with UUID support)
121110 bot . _client . prependListener ( 'resource_pack_send' , ( data ) => {
122111 if ( ! bot . inConfigurationPhase ) return
123- if ( ! data . uuid ) return // Only handle UUID-based resource packs
112+ if ( ! data . uuid ) return
124113
125114 const UUID = require ( 'uuid-1345' )
126- const uuid = new UUID ( data . uuid )
115+ const resourceUuid = new UUID ( data . uuid )
127116
128- // Send ACCEPTED immediately
129117 bot . _client . write ( 'resource_pack_receive' , {
130- uuid : uuid ,
118+ uuid : resourceUuid ,
131119 result : TEXTURE_PACK_RESULTS . ACCEPTED
132120 } )
133121
134- // Send SUCCESSFULLY_LOADED immediately
135122 bot . _client . write ( 'resource_pack_receive' , {
136- uuid : uuid ,
123+ uuid : resourceUuid ,
137124 result : TEXTURE_PACK_RESULTS . SUCCESSFULLY_LOADED
138125 } )
139126 } )
140127
141- // === FINISH CONFIGURATION ===
128+ // === EXIT CONFIGURATION ===
142129
130+ // node-minecraft-protocol already writes the finish_configuration
131+ // acknowledgement and transitions to PLAY state. We just need to
132+ // track it so we can re-enable physics.
143133 bot . _client . on ( 'finish_configuration' , ( ) => {
144- configurationFinished = true
145-
146- // Acknowledge finish_configuration
147- try {
148- bot . _client . write ( 'finish_configuration' , { } )
149- } catch ( err ) {
150- // Ignore if packet doesn't exist for this version
151- }
152-
153- // Exit configuration phase after a short delay
134+ // Small delay to let the play state fully initialize
154135 setTimeout ( ( ) => {
155136 exitConfigurationPhase ( )
156137 } , 500 )
157138 } )
158139
159- // === FALLBACKS ===
160-
161- // Fallback: Exit on login if we're still in configuration phase
162- bot . on ( 'login' , ( ) => {
163- if ( bot . inConfigurationPhase && configurationFinished ) {
164- exitConfigurationPhase ( )
165- }
166- } )
167-
168- // Fallback: Exit on spawn if we're still in configuration phase
140+ // Fallback: exit on spawn if we're still in configuration phase
169141 bot . on ( 'spawn' , ( ) => {
170142 if ( bot . inConfigurationPhase ) {
171143 exitConfigurationPhase ( )
@@ -175,6 +147,6 @@ function inject (bot) {
175147 // Cleanup on end
176148 bot . on ( 'end' , ( ) => {
177149 bot . inConfigurationPhase = false
178- configurationFinished = false
150+ delete bot . _physicsWasEnabled
179151 } )
180- }
152+ }
0 commit comments