Fix boat colors not visible in 1.21->1.21.2 (#4200)

This commit is contained in:
EnZaXD 2024-10-30 10:42:27 +01:00 committed by GitHub
parent af8cbaf439
commit dde599c128
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 363 additions and 11 deletions

View File

@ -31,7 +31,6 @@ import com.viaversion.viaversion.api.rewriter.ComponentRewriter;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.misc.ParticleType;
import com.viaversion.viaversion.api.type.types.version.Types1_21_2;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import com.viaversion.viaversion.protocols.base.ClientboundLoginPackets;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundConfigurationPackets1_20_5;
import com.viaversion.viaversion.protocols.v1_20_3to1_20_5.packet.ServerboundPacket1_20_5;
@ -49,6 +48,7 @@ import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.EntityPacketRe
import com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter.ParticleRewriter1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.EntityTracker1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage;
import com.viaversion.viaversion.rewriter.AttributeRewriter;
import com.viaversion.viaversion.rewriter.SoundRewriter;
@ -230,7 +230,7 @@ public final class Protocol1_21To1_21_2 extends AbstractProtocol<ClientboundPack
@Override
public void init(final UserConnection connection) {
addEntityTracker(connection, new EntityTrackerBase(connection, EntityTypes1_21_2.PLAYER));
addEntityTracker(connection, new EntityTracker1_21_2(connection));
connection.put(new BundleStateTracker());
connection.put(new PlayerPositionStorage());
connection.put(new ChunkLoadTracker());

View File

@ -18,10 +18,13 @@
package com.viaversion.viaversion.protocols.v1_21to1_21_2.rewriter;
import com.viaversion.nbt.tag.CompoundTag;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.data.entity.EntityTracker;
import com.viaversion.viaversion.api.minecraft.RegistryEntry;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_2;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.minecraft.item.Item;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.protocol.remapper.PacketHandlers;
import com.viaversion.viaversion.api.type.Types;
@ -36,9 +39,12 @@ import com.viaversion.viaversion.protocols.v1_21to1_21_2.packet.ServerboundPacke
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.BundleStateTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ChunkLoadTracker;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.ClientVehicleStorage;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.EntityTracker1_21_2;
import com.viaversion.viaversion.protocols.v1_21to1_21_2.storage.PlayerPositionStorage;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.RegistryDataRewriter;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ThreadLocalRandom;
public final class EntityPacketRewriter1_21_2 extends EntityRewriter<ClientboundPacket1_21, Protocol1_21To1_21_2> {
@ -65,6 +71,32 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
registerSetEntityData(ClientboundPackets1_21.SET_ENTITY_DATA, Types1_21.ENTITY_DATA_LIST, Types1_21_2.ENTITY_DATA_LIST);
registerRemoveEntities(ClientboundPackets1_21.REMOVE_ENTITIES);
protocol.appendClientbound(ClientboundPackets1_21.ADD_ENTITY, wrapper -> {
final int entityType = wrapper.get(Types.VAR_INT, 1);
final EntityType type = typeFromId(entityType);
if (type == null || !type.isOrHasParent(EntityTypes1_21_2.ABSTRACT_BOAT)) {
return;
}
final int entityId = wrapper.get(Types.VAR_INT, 0);
final UUID uuid = wrapper.get(Types.UUID, 0);
final double x = wrapper.get(Types.DOUBLE, 0);
final double y = wrapper.get(Types.DOUBLE, 1);
final double z = wrapper.get(Types.DOUBLE, 2);
final float pitch = wrapper.get(Types.BYTE, 0) * 256.0F / 360.0F;
final float yaw = wrapper.get(Types.BYTE, 1) * 256.0F / 360.0F;
final int data = wrapper.get(Types.VAR_INT, 2);
final EntityTracker1_21_2 tracker = tracker(wrapper.user());
final EntityTracker1_21_2.BoatEntity entity = tracker.trackBoatEntity(entityId, uuid, data);
entity.setPosition(x, y, z);
entity.setRotation(yaw, pitch);
});
protocol.registerFinishConfiguration(ClientboundConfigurationPackets1_21.FINISH_CONFIGURATION, wrapper -> {
final PacketWrapper instrumentsPacket = wrapper.create(ClientboundConfigurationPackets1_21.REGISTRY_DATA);
instrumentsPacket.write(Types.STRING, "minecraft:instrument");
@ -193,6 +225,12 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
wrapper.user().remove(ClientVehicleStorage.class);
}
final EntityTracker1_21_2 tracker = tracker(wrapper.user());
final EntityTracker1_21_2.BoatEntity entity = tracker.trackedBoatEntity(vehicleId);
if (entity != null) {
entity.setPassengers(passengerIds);
}
final int clientEntityId = tracker(wrapper.user()).clientEntityId();
for (final int passenger : passengerIds) {
if (passenger == clientEntityId) {
@ -243,11 +281,11 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
});
protocol.registerClientbound(ClientboundPackets1_21.TELEPORT_ENTITY, ClientboundPackets1_21_2.ENTITY_POSITION_SYNC, wrapper -> {
wrapper.passthrough(Types.VAR_INT); // Entity ID
final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity ID
wrapper.passthrough(Types.DOUBLE); // X
wrapper.passthrough(Types.DOUBLE); // Y
wrapper.passthrough(Types.DOUBLE); // Z
final double x = wrapper.passthrough(Types.DOUBLE); // X
final double y = wrapper.passthrough(Types.DOUBLE); // Y
final double z = wrapper.passthrough(Types.DOUBLE); // Z
// Unused...
wrapper.write(Types.DOUBLE, 0D); // Delta movement X
@ -255,11 +293,22 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
wrapper.write(Types.DOUBLE, 0D); // Delta movement Z
// Unpack y and x rot
final byte yaw = wrapper.read(Types.BYTE);
final byte pitch = wrapper.read(Types.BYTE);
wrapper.write(Types.FLOAT, yaw * 360F / 256F);
wrapper.write(Types.FLOAT, pitch * 360F / 256F);
final float yaw = wrapper.read(Types.BYTE) * 360F / 256F;
final float pitch = wrapper.read(Types.BYTE) * 360F / 256F;
wrapper.write(Types.FLOAT, yaw);
wrapper.write(Types.FLOAT, pitch);
final EntityTracker1_21_2 tracker = tracker(wrapper.user());
final EntityTracker1_21_2.BoatEntity trackedEntity = tracker.trackedBoatEntity(entityId);
if (trackedEntity == null) {
return;
}
trackedEntity.setPosition(x, y, z);
trackedEntity.setRotation(yaw, pitch);
});
protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_POS, wrapper -> storeEntityPositionRotation(wrapper, true, false));
protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_POS_ROT, wrapper -> storeEntityPositionRotation(wrapper, true, true));
protocol.registerClientbound(ClientboundPackets1_21.MOVE_ENTITY_ROT, wrapper -> storeEntityPositionRotation(wrapper, false, true));
protocol.registerServerbound(ServerboundPackets1_21_2.MOVE_PLAYER_POS, wrapper -> {
wrapper.passthrough(Types.DOUBLE); // X
@ -326,6 +375,27 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
wrapper.write(Types.BOOLEAN, (data & 1) != 0); // On ground, ignoring horizontal collision data
}
private void storeEntityPositionRotation(final PacketWrapper wrapper, final boolean position, final boolean rotation) {
final int entityId = wrapper.passthrough(Types.VAR_INT); // Entity id
final EntityTracker1_21_2 tracker = tracker(wrapper.user());
final EntityTracker1_21_2.BoatEntity trackedEntity = tracker.trackedBoatEntity(entityId);
if (trackedEntity == null) {
return;
}
if (position) {
final double x = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta X
final double y = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta Y
final double z = wrapper.passthrough(Types.SHORT) / 4096.0; // Delta Z
trackedEntity.setPosition(trackedEntity.x() + x, trackedEntity.y() + y, trackedEntity.z() + z);
}
if (rotation) {
final float yaw = wrapper.passthrough(Types.BYTE) * 360.0F / 256.0F;
final float pitch = wrapper.passthrough(Types.BYTE) * 360.0F / 256.0F;
trackedEntity.setRotation(yaw, pitch);
}
}
@Override
protected void registerRewrites() {
filter().mapDataType(Types1_21_2.ENTITY_DATA_TYPES::byId);
@ -341,7 +411,84 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
);
registerBlockStateHandler(EntityTypes1_21_2.ABSTRACT_MINECART, 11);
filter().type(EntityTypes1_21_2.ABSTRACT_BOAT).removeIndex(11); // Goodbye boat type
filter().type(EntityTypes1_21_2.ABSTRACT_BOAT).handler((event, data) -> {
final int dataIndex = event.index();
// Boat type - now set as own entity type
// Idea is to remove the old entity, then add a new one and re-apply entity data and passengers
if (dataIndex > 11) {
event.setIndex(dataIndex - 1);
return;
}
if (dataIndex != 11) {
return;
}
event.cancel();
final EntityTracker1_21_2 tracker = tracker(event.user());
final EntityTracker1_21_2.BoatEntity entity = tracker.trackedBoatEntity(event.entityId());
if (entity == null) {
return;
}
final boolean isBundling = event.user().get(BundleStateTracker.class).isBundling();
if (!isBundling) {
final PacketWrapper bundleStart = PacketWrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER, event.user());
bundleStart.send(Protocol1_21To1_21_2.class);
}
// Remove old entity
final PacketWrapper removeEntityPacket = PacketWrapper.create(ClientboundPackets1_21_2.REMOVE_ENTITIES, event.user());
removeEntityPacket.write(Types.VAR_INT_ARRAY_PRIMITIVE, new int[] { event.entityId() });
removeEntityPacket.send(Protocol1_21To1_21_2.class);
// Detect correct boat entity type from entity data
final int boatType = (int) data.getValue();
EntityType entityType;
if (tracker.entityType(event.entityId()).isOrHasParent(EntityTypes1_21_2.ABSTRACT_CHEST_BOAT)) {
entityType = entityTypeFromChestBoatType(boatType);
} else {
entityType = entityTypeFromBoatType(boatType);
}
// Spawn new entity
final PacketWrapper spawnEntityPacket = PacketWrapper.create(ClientboundPackets1_21_2.ADD_ENTITY, event.user());
spawnEntityPacket.write(Types.VAR_INT, event.entityId()); // Entity ID
spawnEntityPacket.write(Types.UUID, entity.uuid()); // Entity UUID
spawnEntityPacket.write(Types.VAR_INT, entityType.getId()); // Entity type
spawnEntityPacket.write(Types.DOUBLE, entity.x()); // X
spawnEntityPacket.write(Types.DOUBLE, entity.y()); // Y
spawnEntityPacket.write(Types.DOUBLE, entity.z()); // Z
spawnEntityPacket.write(Types.BYTE, (byte) Math.floor(entity.pitch() * 256.0F / 360.0F)); // Pitch
spawnEntityPacket.write(Types.BYTE, (byte) Math.floor(entity.yaw() * 256.0F / 360.0F)); // Yaw
spawnEntityPacket.write(Types.BYTE, (byte) 0); // Head yaw
spawnEntityPacket.write(Types.VAR_INT, entity.data()); // Data
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity X
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity Y
spawnEntityPacket.write(Types.SHORT, (short) 0); // Velocity Z
spawnEntityPacket.send(Protocol1_21To1_21_2.class);
// Update tracked entity in storage with new entity type
tracker.updateBoatType(event.entityId(), entityType);
// Re-apply entity data previously set
final PacketWrapper setEntityDataPacket = PacketWrapper.create(ClientboundPackets1_21_2.SET_ENTITY_DATA, event.user());
setEntityDataPacket.write(Types.VAR_INT, event.entityId());
setEntityDataPacket.write(Types1_21_2.ENTITY_DATA_LIST, entity.entityData());
setEntityDataPacket.send(Protocol1_21To1_21_2.class);
// Re-attach all passengers
if (entity.passengers() != null) {
final PacketWrapper setPassengersPacket = PacketWrapper.create(ClientboundPackets1_21_2.SET_PASSENGERS, event.user());
setPassengersPacket.write(Types.VAR_INT, event.entityId());
setPassengersPacket.write(Types.VAR_INT_ARRAY_PRIMITIVE, entity.passengers());
setPassengersPacket.send(Protocol1_21To1_21_2.class);
}
if (!isBundling) {
final PacketWrapper bundleEnd = PacketWrapper.create(ClientboundPackets1_21_2.BUNDLE_DELIMITER, event.user());
bundleEnd.send(Protocol1_21To1_21_2.class);
}
});
filter().type(EntityTypes1_21_2.SALMON).addIndex(17); // Data type
filter().type(EntityTypes1_21_2.AGEABLE_WATER_CREATURE).addIndex(16); // Baby
@ -349,6 +496,76 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
filter().type(EntityTypes1_21_2.ABSTRACT_ARROW).addIndex(10); // In ground
}
@Override
public void handleEntityData(final int entityId, final List<EntityData> dataList, final UserConnection connection) {
super.handleEntityData(entityId, dataList, connection);
final EntityTracker1_21_2 tracker = tracker(connection);
final EntityType entityType = tracker.entityType(entityId);
if (entityType != null && !entityType.isOrHasParent(EntityTypes1_21_2.ABSTRACT_BOAT)) {
return;
}
final List<EntityData> entityData = tracker.trackedBoatEntity(entityId).entityData();
entityData.removeIf(first -> dataList.stream().anyMatch(second -> first.id() == second.id()));
for (final EntityData data : dataList) {
final Object value = data.value();
if (value instanceof Item item) {
entityData.add(new EntityData(data.id(), data.dataType(), item.copy()));
} else {
entityData.add(new EntityData(data.id(), data.dataType(), value));
}
}
}
private EntityType entityTypeFromBoatType(final int boatType) {
if (boatType == 0) {
return EntityTypes1_21_2.OAK_BOAT;
} else if (boatType == 1) {
return EntityTypes1_21_2.SPRUCE_BOAT;
} else if (boatType == 2) {
return EntityTypes1_21_2.BIRCH_BOAT;
} else if (boatType == 3) {
return EntityTypes1_21_2.JUNGLE_BOAT;
} else if (boatType == 4) {
return EntityTypes1_21_2.ACACIA_BOAT;
} else if (boatType == 5) {
return EntityTypes1_21_2.CHERRY_BOAT;
} else if (boatType == 6) {
return EntityTypes1_21_2.DARK_OAK_BOAT;
} else if (boatType == 7) {
return EntityTypes1_21_2.MANGROVE_BOAT;
} else if (boatType == 8) {
return EntityTypes1_21_2.BAMBOO_RAFT;
} else {
return EntityTypes1_21_2.OAK_BOAT; // Fallback
}
}
private EntityType entityTypeFromChestBoatType(final int chestBoatType) {
if (chestBoatType == 0) {
return EntityTypes1_21_2.OAK_CHEST_BOAT;
} else if (chestBoatType == 1) {
return EntityTypes1_21_2.SPRUCE_CHEST_BOAT;
} else if (chestBoatType == 2) {
return EntityTypes1_21_2.BIRCH_CHEST_BOAT;
} else if (chestBoatType == 3) {
return EntityTypes1_21_2.JUNGLE_CHEST_BOAT;
} else if (chestBoatType == 4) {
return EntityTypes1_21_2.ACACIA_CHEST_BOAT;
} else if (chestBoatType == 5) {
return EntityTypes1_21_2.CHERRY_CHEST_BOAT;
} else if (chestBoatType == 6) {
return EntityTypes1_21_2.DARK_OAK_CHEST_BOAT;
} else if (chestBoatType == 7) {
return EntityTypes1_21_2.MANGROVE_CHEST_BOAT;
} else if (chestBoatType == 8) {
return EntityTypes1_21_2.BAMBOO_CHEST_RAFT;
} else {
return EntityTypes1_21_2.OAK_CHEST_BOAT; // Fallback
}
}
@Override
public EntityType typeFromId(final int type) {
return EntityTypes1_21_2.getTypeFromId(type);

View File

@ -0,0 +1,135 @@
/*
* This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion
* Copyright (C) 2016-2024 ViaVersion and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.viaversion.viaversion.protocols.v1_21to1_21_2.storage;
import com.viaversion.viaversion.api.connection.UserConnection;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_21_2;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.data.entity.EntityTrackerBase;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public final class EntityTracker1_21_2 extends EntityTrackerBase {
private final Int2ObjectMap<BoatEntity> boats = new Int2ObjectOpenHashMap<>();
public EntityTracker1_21_2(final UserConnection connection) {
super(connection, EntityTypes1_21_2.PLAYER);
}
public BoatEntity trackBoatEntity(final int entityId, final UUID uuid, final int data) {
final BoatEntity entity = new BoatEntity(uuid, data);
boats.put(entityId, entity);
return entity;
}
public BoatEntity trackedBoatEntity(final int entityId) {
return boats.get(entityId);
}
@Override
public void removeEntity(final int id) {
super.removeEntity(id);
boats.remove(id);
}
public void updateBoatType(final int entityId, final EntityType type) {
final BoatEntity entity = boats.get(entityId);
removeEntity(entityId);
boats.put(entityId, entity);
addEntity(entityId, type);
}
public static class BoatEntity {
private final List<EntityData> entityData = new ArrayList<>();
private final UUID uuid;
private final int data;
private double x;
private double y;
private double z;
private float yaw;
private float pitch;
private int[] passengers;
public BoatEntity(final UUID uuid, final int data) {
this.uuid = uuid;
this.data = data;
}
public void setPosition(final double x, final double y, final double z) {
this.x = x;
this.y = y;
this.z = z;
}
public void setRotation(final float yaw, final float pitch) {
this.yaw = yaw;
this.pitch = pitch;
}
public void setPassengers(final int[] passengers) {
this.passengers = passengers;
}
public UUID uuid() {
return uuid;
}
public int data() {
return data;
}
public double x() {
return x;
}
public double y() {
return y;
}
public double z() {
return z;
}
public float yaw() {
return yaw;
}
public float pitch() {
return pitch;
}
public List<EntityData> entityData() {
return entityData;
}
public int[] passengers() {
return passengers;
}
}
}