Skip to content

Commit 9e7c853

Browse files
Term4florianreuth
andauthored
Fix splash potions turning into drinkable potions in 1.9->1.8 (#703)
Co-authored-by: Florian Reuth <git@florianreuth.de>
1 parent 315a1a0 commit 9e7c853

3 files changed

Lines changed: 98 additions & 6 deletions

File tree

common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/BlockItemPacketRewriter1_9.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,8 @@ public Item handleItemToServer(UserConnection connection, Item item) {
375375
item.setData((short) 0);
376376
}
377377

378-
if (item.identifier() == 373 && (tag == null || !tag.contains("Potion"))) { // Potions
378+
if (item.identifier() == 373) { // Potions
379+
// Restore the splash id even when a Potion tag is present (e.g. items re-sent by a creative mode client)
379380
if (item.data() >= 16384) {
380381
item.setIdentifier(438);
381382
item.setData((short) (item.data() - 8192));

common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/rewriter/EntityPacketRewriter1_9.java

Lines changed: 77 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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())) {

common/src/main/java/com/viaversion/viarewind/protocol/v1_9to1_8/storage/EntityTracker1_9.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public class EntityTracker1_9 extends EntityTrackerBase {
3939
private final Int2ObjectMap<Vector> offsets = new Int2ObjectOpenHashMap<>();
4040
private final Int2IntMap status = new Int2IntOpenHashMap();
4141
private final IntSet handActive = new IntOpenHashSet();
42+
private final Int2ObjectMap<PendingPotionEntity> pendingPotions = new Int2ObjectOpenHashMap<>();
4243

4344
public EntityTracker1_9(UserConnection connection) {
4445
super(connection, EntityTypes1_9.EntityType.PLAYER);
@@ -50,6 +51,7 @@ public TrackedEntity removeEntity(int id) {
5051
offsets.remove(id);
5152
status.remove(id);
5253
handActive.remove(id);
54+
pendingPotions.remove(id);
5355

5456
vehicles.forEach((vehicle, passengers) -> passengers.rem(id));
5557
vehicles.int2ObjectEntrySet().removeIf(entry -> entry.getValue().isEmpty());
@@ -105,4 +107,21 @@ public void setHandActive(final int id, final boolean active) {
105107
handActive.remove(id);
106108
}
107109
}
110+
111+
public Int2ObjectMap<PendingPotionEntity> getPendingPotions() {
112+
return pendingPotions;
113+
}
114+
115+
public record PendingPotionEntity(int x, int y, int z, byte pitch, byte yaw, short velocityX, short velocityY, short velocityZ) {
116+
117+
public PendingPotionEntity withPosition(final int x, final int y, final int z, final byte pitch, final byte yaw) {
118+
return new PendingPotionEntity(x, y, z, pitch, yaw, velocityX, velocityY, velocityZ);
119+
}
120+
121+
public PendingPotionEntity withVelocity(final short velocityX, final short velocityY, final short velocityZ) {
122+
return new PendingPotionEntity(x, y, z, pitch, yaw, velocityX, velocityY, velocityZ);
123+
}
124+
125+
}
126+
108127
}

0 commit comments

Comments
 (0)