@@ -134,11 +134,24 @@ public void register() {
134134 }
135135 }
136136
137- if (data > 0 ) {
138- wrapper .passthrough (Types .SHORT ); // Velocity x
139- wrapper .passthrough (Types .SHORT ); // Velocity y
140- wrapper .passthrough (Types .SHORT ); // Velocity z
141- } else {
137+ if (type .is (EntityTypes1_9 .EntityType .POTION ) && data > 0 ) {
138+ // 1.8 clients read the potion type from the object data, but newer versions only
139+ // send it in the entity data - the next packet. Held until then, see handleEntityData
140+ wrapper .cancel ();
141+ final int x = wrapper .get (Types .INT , 0 );
142+ final int y = wrapper .get (Types .INT , 1 );
143+ final int z = wrapper .get (Types .INT , 2 );
144+ final byte pitch = wrapper .get (Types .BYTE , 1 );
145+ final byte yaw = wrapper .get (Types .BYTE , 2 );
146+ final short velocityX = wrapper .passthrough (Types .SHORT );
147+ final short velocityY = wrapper .passthrough (Types .SHORT );
148+ final short velocityZ = wrapper .passthrough (Types .SHORT );
149+ final EntityTracker1_9 tracker = tracker (wrapper .user ());
150+ tracker .getPendingPotions ().put (entityId , new EntityTracker1_9 .PendingPotionEntity (x , y , z , pitch , yaw , velocityX , velocityY , velocityZ ));
151+ return ;
152+ }
153+
154+ if (data <= 0 ) {
142155 final short velocityX = wrapper .read (Types .SHORT );
143156 final short velocityY = wrapper .read (Types .SHORT );
144157 final short velocityZ = wrapper .read (Types .SHORT );
@@ -444,6 +457,19 @@ public void register() {
444457 }
445458 });
446459
460+ protocol .registerClientbound (ClientboundPackets1_9 .SET_ENTITY_MOTION , wrapper -> {
461+ final int entityId = wrapper .passthrough (Types .VAR_INT );
462+ final EntityTracker1_9 tracker = tracker (wrapper .user ());
463+ final EntityTracker1_9 .PendingPotionEntity pending = tracker .getPendingPotions ().get (entityId );
464+ if (pending != null ) {
465+ wrapper .cancel ();
466+ final short velocityX = wrapper .read (Types .SHORT );
467+ final short velocityY = wrapper .read (Types .SHORT );
468+ final short velocityZ = wrapper .read (Types .SHORT );
469+ tracker .getPendingPotions ().put (entityId , pending .withVelocity (velocityX , velocityY , velocityZ ));
470+ }
471+ });
472+
447473 protocol .registerClientbound (ClientboundPackets1_9 .TELEPORT_ENTITY , new PacketHandlers () {
448474 @ Override
449475 public void register () {
@@ -458,6 +484,18 @@ public void register() {
458484 final int entityId = wrapper .get (Types .VAR_INT , 0 );
459485
460486 final EntityTracker1_9 tracker = wrapper .user ().getEntityTracker (Protocol1_9To1_8 .class );
487+ final EntityTracker1_9 .PendingPotionEntity pending = tracker .getPendingPotions ().get (entityId );
488+ if (pending != null ) {
489+ wrapper .cancel ();
490+ final int x = wrapper .get (Types .INT , 0 );
491+ final int y = wrapper .get (Types .INT , 1 );
492+ final int z = wrapper .get (Types .INT , 2 );
493+ final byte yaw = wrapper .get (Types .BYTE , 0 );
494+ final byte pitch = wrapper .get (Types .BYTE , 1 );
495+ tracker .getPendingPotions ().put (entityId , pending .withPosition (x , y , z , pitch , yaw ));
496+ return ;
497+ }
498+
461499 if (tracker .entityType (entityId ) == EntityTypes1_9 .EntityType .BOAT ) {
462500 byte yaw = wrapper .get (Types .BYTE , 0 );
463501 yaw -= 64 ;
@@ -541,8 +579,42 @@ protected void registerRewrites() {
541579 filter ().handler (this ::handleEntityData );
542580 }
543581
582+ private void sendDelayedPotionSpawn (final EntityDataHandlerEvent event , final EntityTracker1_9 tracker , final Item item ) {
583+ final EntityTracker1_9 .PendingPotionEntity spawn = tracker .getPendingPotions ().remove (event .entityId ());
584+ if (spawn == null ) {
585+ return ;
586+ }
587+
588+ final Item converted = protocol .getItemRewriter ().handleItemToClient (event .user (), item );
589+ short data = converted == null ? 0 : converted .data ();
590+ if (data <= 0 ) {
591+ data = 16384 ; // Unmapped potion, at least display a splash bottle
592+ }
593+
594+ final PacketWrapper addEntity = PacketWrapper .create (ClientboundPackets1_8 .ADD_ENTITY , event .user ());
595+ addEntity .write (Types .VAR_INT , event .entityId ());
596+ addEntity .write (Types .BYTE , (byte ) EntityTypes1_9 .ObjectType .POTION .getId ());
597+ addEntity .write (Types .INT , spawn .x ());
598+ addEntity .write (Types .INT , spawn .y ());
599+ addEntity .write (Types .INT , spawn .z ());
600+ addEntity .write (Types .BYTE , spawn .pitch ());
601+ addEntity .write (Types .BYTE , spawn .yaw ());
602+ addEntity .write (Types .INT , (int ) data );
603+ addEntity .write (Types .SHORT , spawn .velocityX ());
604+ addEntity .write (Types .SHORT , spawn .velocityY ());
605+ addEntity .write (Types .SHORT , spawn .velocityZ ());
606+ addEntity .send (Protocol1_9To1_8 .class ); // Before the entity data is sent
607+ }
608+
544609 private void handleEntityData (EntityDataHandlerEvent event , EntityData entityData ) {
545610 final EntityTracker1_9 tracker = tracker (event .user ());
611+ if (event .entityType () == EntityTypes1_9 .EntityType .POTION && entityData .value () instanceof Item potionItem ) {
612+ // No 1.8 equivalent; supplies the object data of the held-back spawn. Matched by value type as the index is version dependent
613+ this .sendDelayedPotionSpawn (event , tracker , potionItem );
614+ event .cancel ();
615+ return ;
616+ }
617+
546618 if (entityData .id () == EntityDataIndex1_9 .ENTITY_STATUS .getIndex ()) {
547619 tracker .getStatus ().put (event .entityId (), (Byte ) entityData .value ());
548620 if (tracker .isHandActive (event .entityId ())) {
0 commit comments