Skip to content

Commit dde599c

Browse files
Fix boat colors not visible in 1.21->1.21.2 (ViaVersion#4200)
1 parent af8cbaf commit dde599c

File tree

3 files changed

+363
-11
lines changed

3 files changed

+363
-11
lines changed

common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/Protocol1_21To1_21_2.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import com.viaversion.viaversion.api.type.Types;
3232
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
3333
import com.viaversion.viaversion.api.type.types.version.Types1_21_2;
34-
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
3534
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
3635
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5;
3736
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
@@ -49,6 +48,7 @@
4948
import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.ParticleRewriter1_21_2;
5049
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker;
5150
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker;
51+
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.EntityTracker1_21_2;
5252
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage;
5353
import com.viaversion.viaversion.rewriter.AttributeRewriter;
5454
import com.viaversion.viaversion.rewriter.SoundRewriter;
@@ -230,7 +230,7 @@ protected void onMappingDataLoaded() {
230230

231231
@Override
232232
public void init(final UserConnection connection) {
233-
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_2.PLAYER));
233+
addEntityTracker(connection, new EntityTracker1_21_2(connection));
234234
connection.put(new BundleStateTracker());
235235
connection.put(new PlayerPositionStorage());
236236
connection.put(new ChunkLoadTracker());

common/src/main/java/com/viaversion/viaversion/protocols/v1_21to1_21_2/rewriter/EntityPacketRewriter1_21_2.java

Lines changed: 226 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,13 @@
1818
package com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter;
1919

2020
import com.viaversion.nbt.tag.CompoundTag;
21+
import com.viaversion.viaversion.api.connection.UserConnection;
2122
import com.viaversion.viaversion.api.data.entity.EntityTracker;
2223
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
2324
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
2425
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_2;
26+
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
27+
import com.viaversion.viaversion.api.minecraft.item.Item;
2528
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
2629
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
2730
import com.viaversion.viaversion.api.type.Types;
@@ -36,9 +39,12 @@
3639
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker;
3740
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker;
3841
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ClientVehicleStorage;
42+
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.EntityTracker1_21_2;
3943
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage;
4044
import com.viaversion.viaversion.rewriter.EntityRewriter;
4145
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
46+
import java.util.List;
47+
import java.util.UUID;
4248
import java.util.concurrent.ThreadLocalRandom;
4349

4450
public final class EntityPacketRewriter1_21_2 extends EntityRewriter<ClientboundPacket1_21, Protocol1_21To1_21_2> {
@@ -65,6 +71,32 @@ public void registerPackets() {
6571
registerSetEntityData(ClientboundPackets1_21.SET_ENTITY_DATA, Types1_21.ENTITY_DATA_LIST, Types1_21_2.ENTITY_DATA_LIST);
6672
registerRemoveEntities(ClientboundPackets1_21.REMOVE_ENTITIES);
6773

74+
protocol.appendClientbound(ClientboundPackets1_21.ADD_ENTITY, wrapper -> {
75+
final int entityType = wrapper.get(Types.VAR_INT, 1);
76+
77+
final EntityType type = typeFromId(entityType);
78+
if (type == null || !type.isOrHasParent(EntityTypes1_21_2.ABSTRACT_BOAT)) {
79+
return;
80+
}
81+
82+
final int entityId = wrapper.get(Types.VAR_INT, 0);
83+
final UUID uuid = wrapper.get(Types.UUID, 0);
84+
85+
final double x = wrapper.get(Types.DOUBLE, 0);
86+
final double y = wrapper.get(Types.DOUBLE, 1);
87+
final double z = wrapper.get(Types.DOUBLE, 2);
88+
89+
final float pitch = wrapper.get(Types.BYTE, 0) * 256.0F / 360.0F;
90+
final float yaw = wrapper.get(Types.BYTE, 1) * 256.0F / 360.0F;
91+
92+
final int data = wrapper.get(Types.VAR_INT, 2);
93+
94+
final EntityTracker1_21_2 tracker = tracker(wrapper.user());
95+
final EntityTracker1_21_2.BoatEntity entity = tracker.trackBoatEntity(entityId, uuid, data);
96+
entity.setPosition(x, y, z);
97+
entity.setRotation(yaw, pitch);
98+
});
99+
68100
protocol.registerFinishConfiguration(ClientboundConfigurationPackets1_21.FINISH_CONFIGURATION, wrapper -> {
69101
final PacketWrapper instrumentsPacket = wrapper.create(ClientboundConfigurationPackets1_21.REGISTRY_DATA);
70102
instrumentsPacket.write(Types.STRING, "minecraft:instrument");
@@ -193,6 +225,12 @@ public void register() {
193225
wrapper.user().remove(ClientVehicleStorage.class);
194226
}
195227

228+
final EntityTracker1_21_2 tracker = tracker(wrapper.user());
229+
final EntityTracker1_21_2.BoatEntity entity = tracker.trackedBoatEntity(vehicleId);
230+
if (entity != null) {
231+
entity.setPassengers(passengerIds);
232+
}
233+
196234
final int clientEntityId = tracker(wrapper.user()).clientEntityId();
197235
for (final int passenger : passengerIds) {
198236
if (passenger == clientEntityId) {
@@ -243,23 +281,34 @@ public void register() {
243281
});
244282

245283
protocol.registerClientbound(ClientboundPackets1_21.TELEPORT_ENTITY, ClientboundPackets1_21_2.ENTITY_POSITION_SYNC, wrapper -> {
246-
wrapper.passthrough(Types.VAR_INT); // Entity ID
284+
final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity ID
247285

248-
wrapper.passthrough(Types.DOUBLE); // X
249-
wrapper.passthrough(Types.DOUBLE); // Y
250-
wrapper.passthrough(Types.DOUBLE); // Z
286+
final double x = wrapper.passthrough(Types.DOUBLE); // X
287+
final double y = wrapper.passthrough(Types.DOUBLE); // Y
288+
final double z = wrapper.passthrough(Types.DOUBLE); // Z
251289

252290
// Unused...
253291
wrapper.write(Types.DOUBLE, 0D); // Delta movement X
254292
wrapper.write(Types.DOUBLE, 0D); // Delta movement Y
255293
wrapper.write(Types.DOUBLE, 0D); // Delta movement Z
256294

257295
// Unpack y and x rot
258-
final byte yaw = wrapper.read(Types.BYTE);
259-
final byte pitch = wrapper.read(Types.BYTE);
260-
wrapper.write(Types.FLOAT, yaw * 360F / 256F);
261-
wrapper.write(Types.FLOAT, pitch * 360F / 256F);
296+
final float yaw = wrapper.read(Types.BYTE) * 360F / 256F;
297+
final float pitch = wrapper.read(Types.BYTE) * 360F / 256F;
298+
wrapper.write(Types.FLOAT, yaw);
299+
wrapper.write(Types.FLOAT, pitch);
300+
301+
final EntityTracker1_21_2 tracker = tracker(wrapper.user());
302+
final EntityTracker1_21_2.BoatEntity trackedEntity = tracker.trackedBoatEntity(entityId);
303+
if (trackedEntity == null) {
304+
return;
305+
}
306+
trackedEntity.setPosition(x, y, z);
307+
trackedEntity.setRotation(yaw, pitch);
262308
});
309+
protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_POS, wrapper -> storeEntityPositionRotation(wrapper, true, false));
310+
protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_POS_ROT, wrapper -> storeEntityPositionRotation(wrapper, true, true));
311+
protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_ROT, wrapper -> storeEntityPositionRotation(wrapper, false, true));
263312

264313
protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_POS, wrapper -> {
265314
wrapper.passthrough(Types.DOUBLE); // X
@@ -326,6 +375,27 @@ private void readOnGround(final PacketWrapper wrapper) {
326375
wrapper.write(Types.BOOLEAN, (data & 1) != 0); // On ground, ignoring horizontal collision data
327376
}
328377

378+
private void storeEntityPositionRotation(final PacketWrapper wrapper, final boolean position, final boolean rotation) {
379+
final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity id
380+
381+
final EntityTracker1_21_2 tracker = tracker(wrapper.user());
382+
final EntityTracker1_21_2.BoatEntity trackedEntity = tracker.trackedBoatEntity(entityId);
383+
if (trackedEntity == null) {
384+
return;
385+
}
386+
if (position) {
387+
final double x = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta X
388+
final double y = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta Y
389+
final double z = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta Z
390+
trackedEntity.setPosition(trackedEntity.x() + x, trackedEntity.y() + y, trackedEntity.z() + z);
391+
}
392+
if (rotation) {
393+
final float yaw = wrapper.passthrough(Types.BYTE) * 360.0F / 256.0F;
394+
final float pitch = wrapper.passthrough(Types.BYTE) * 360.0F / 256.0F;
395+
trackedEntity.setRotation(yaw, pitch);
396+
}
397+
}
398+
329399
@Override
330400
protected void registerRewrites() {
331401
filter().mapDataType(Types1_21_2.ENTITY_DATA_TYPES::byId);
@@ -341,14 +411,161 @@ protected void registerRewrites() {
341411
);
342412
registerBlockStateHandler(EntityTypes1_21_2.ABSTRACT_MINECART, 11);
343413

344-
filter().type(EntityTypes1_21_2.ABSTRACT_BOAT).removeIndex(11); // Goodbye boat type
414+
filter().type(EntityTypes1_21_2.ABSTRACT_BOAT).handler((event, data) -> {
415+
final int dataIndex = event.index();
416+
// Boat type - now set as own entity type
417+
// Idea is to remove the old entity, then add a new one and re-apply entity data and passengers
418+
if (dataIndex > 11) {
419+
event.setIndex(dataIndex - 1);
420+
return;
421+
}
422+
if (dataIndex != 11) {
423+
return;
424+
}
425+
event.cancel();
426+
427+
final EntityTracker1_21_2 tracker = tracker(event.user());
428+
final EntityTracker1_21_2.BoatEntity entity = tracker.trackedBoatEntity(event.entityId());
429+
if (entity == null) {
430+
return;
431+
}
432+
433+
final boolean isBundling = event.user().get(BundleStateTracker.class).isBundling();
434+
if (!isBundling) {
435+
final PacketWrapper bundleStart = PacketWrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER, event.user());
436+
bundleStart.send(Protocol1_21To1_21_2.class);
437+
}
438+
439+
// Remove old entity
440+
final PacketWrapper removeEntityPacket = PacketWrapper.create(ClientboundPackets1_21_2.REMOVE_ENTITIES, event.user());
441+
removeEntityPacket.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[] { event.entityId() });
442+
removeEntityPacket.send(Protocol1_21To1_21_2.class);
443+
444+
// Detect correct boat entity type from entity data
445+
final int boatType = (int) data.getValue();
446+
EntityType entityType;
447+
if (tracker.entityType(event.entityId()).isOrHasParent(EntityTypes1_21_2.ABSTRACT_CHEST_BOAT)) {
448+
entityType = entityTypeFromChestBoatType(boatType);
449+
} else {
450+
entityType = entityTypeFromBoatType(boatType);
451+
}
452+
453+
// Spawn new entity
454+
final PacketWrapper spawnEntityPacket = PacketWrapper.create(ClientboundPackets1_21_2.ADD_ENTITY, event.user());
455+
spawnEntityPacket.write(Types.VAR_INT, event.entityId()); // Entity ID
456+
spawnEntityPacket.write(Types.UUID, entity.uuid()); // Entity UUID
457+
spawnEntityPacket.write(Types.VAR_INT, entityType.getId()); // Entity type
458+
spawnEntityPacket.write(Types.DOUBLE, entity.x()); // X
459+
spawnEntityPacket.write(Types.DOUBLE, entity.y()); // Y
460+
spawnEntityPacket.write(Types.DOUBLE, entity.z()); // Z
461+
spawnEntityPacket.write(Types.BYTE, (byte) Math.floor(entity.pitch() * 256.0F / 360.0F)); // Pitch
462+
spawnEntityPacket.write(Types.BYTE, (byte) Math.floor(entity.yaw() * 256.0F / 360.0F)); // Yaw
463+
spawnEntityPacket.write(Types.BYTE, (byte) 0); // Head yaw
464+
spawnEntityPacket.write(Types.VAR_INT, entity.data()); // Data
465+
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity X
466+
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity Y
467+
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity Z
468+
spawnEntityPacket.send(Protocol1_21To1_21_2.class);
469+
470+
// Update tracked entity in storage with new entity type
471+
tracker.updateBoatType(event.entityId(), entityType);
472+
473+
// Re-apply entity data previously set
474+
final PacketWrapper setEntityDataPacket = PacketWrapper.create(ClientboundPackets1_21_2.SET_ENTITY_DATA, event.user());
475+
setEntityDataPacket.write(Types.VAR_INT, event.entityId());
476+
setEntityDataPacket.write(Types1_21_2.ENTITY_DATA_LIST, entity.entityData());
477+
setEntityDataPacket.send(Protocol1_21To1_21_2.class);
478+
479+
// Re-attach all passengers
480+
if (entity.passengers() != null) {
481+
final PacketWrapper setPassengersPacket = PacketWrapper.create(ClientboundPackets1_21_2.SET_PASSENGERS, event.user());
482+
setPassengersPacket.write(Types.VAR_INT, event.entityId());
483+
setPassengersPacket.write(Types.VAR_INT_ARRAY_PRIMITIVE, entity.passengers());
484+
setPassengersPacket.send(Protocol1_21To1_21_2.class);
485+
}
486+
487+
if (!isBundling) {
488+
final PacketWrapper bundleEnd = PacketWrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER, event.user());
489+
bundleEnd.send(Protocol1_21To1_21_2.class);
490+
}
491+
});
345492

346493
filter().type(EntityTypes1_21_2.SALMON).addIndex(17); // Data type
347494
filter().type(EntityTypes1_21_2.AGEABLE_WATER_CREATURE).addIndex(16); // Baby
348495

349496
filter().type(EntityTypes1_21_2.ABSTRACT_ARROW).addIndex(10); // In ground
350497
}
351498

499+
@Override
500+
public void handleEntityData(final int entityId, final List<EntityData> dataList, final UserConnection connection) {
501+
super.handleEntityData(entityId, dataList, connection);
502+
503+
final EntityTracker1_21_2 tracker = tracker(connection);
504+
final EntityType entityType = tracker.entityType(entityId);
505+
if (entityType != null && !entityType.isOrHasParent(EntityTypes1_21_2.ABSTRACT_BOAT)) {
506+
return;
507+
}
508+
509+
final List<EntityData> entityData = tracker.trackedBoatEntity(entityId).entityData();
510+
entityData.removeIf(first -> dataList.stream().anyMatch(second -> first.id() == second.id()));
511+
for (final EntityData data : dataList) {
512+
final Object value = data.value();
513+
if (value instanceof Item item) {
514+
entityData.add(new EntityData(data.id(), data.dataType(), item.copy()));
515+
} else {
516+
entityData.add(new EntityData(data.id(), data.dataType(), value));
517+
}
518+
}
519+
}
520+
521+
private EntityType entityTypeFromBoatType(final int boatType) {
522+
if (boatType == 0) {
523+
return EntityTypes1_21_2.OAK_BOAT;
524+
} else if (boatType == 1) {
525+
return EntityTypes1_21_2.SPRUCE_BOAT;
526+
} else if (boatType == 2) {
527+
return EntityTypes1_21_2.BIRCH_BOAT;
528+
} else if (boatType == 3) {
529+
return EntityTypes1_21_2.JUNGLE_BOAT;
530+
} else if (boatType == 4) {
531+
return EntityTypes1_21_2.ACACIA_BOAT;
532+
} else if (boatType == 5) {
533+
return EntityTypes1_21_2.CHERRY_BOAT;
534+
} else if (boatType == 6) {
535+
return EntityTypes1_21_2.DARK_OAK_BOAT;
536+
} else if (boatType == 7) {
537+
return EntityTypes1_21_2.MANGROVE_BOAT;
538+
} else if (boatType == 8) {
539+
return EntityTypes1_21_2.BAMBOO_RAFT;
540+
} else {
541+
return EntityTypes1_21_2.OAK_BOAT; // Fallback
542+
}
543+
}
544+
545+
private EntityType entityTypeFromChestBoatType(final int chestBoatType) {
546+
if (chestBoatType == 0) {
547+
return EntityTypes1_21_2.OAK_CHEST_BOAT;
548+
} else if (chestBoatType == 1) {
549+
return EntityTypes1_21_2.SPRUCE_CHEST_BOAT;
550+
} else if (chestBoatType == 2) {
551+
return EntityTypes1_21_2.BIRCH_CHEST_BOAT;
552+
} else if (chestBoatType == 3) {
553+
return EntityTypes1_21_2.JUNGLE_CHEST_BOAT;
554+
} else if (chestBoatType == 4) {
555+
return EntityTypes1_21_2.ACACIA_CHEST_BOAT;
556+
} else if (chestBoatType == 5) {
557+
return EntityTypes1_21_2.CHERRY_CHEST_BOAT;
558+
} else if (chestBoatType == 6) {
559+
return EntityTypes1_21_2.DARK_OAK_CHEST_BOAT;
560+
} else if (chestBoatType == 7) {
561+
return EntityTypes1_21_2.MANGROVE_CHEST_BOAT;
562+
} else if (chestBoatType == 8) {
563+
return EntityTypes1_21_2.BAMBOO_CHEST_RAFT;
564+
} else {
565+
return EntityTypes1_21_2.OAK_CHEST_BOAT; // Fallback
566+
}
567+
}
568+
352569
@Override
353570
public EntityType typeFromId(final int type) {
354571
return EntityTypes1_21_2.getTypeFromId(type);

0 commit comments

Comments
 (0)