Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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.viabackwards.api.entities;


import com.viaversion.viaversion.api.data.entity.StoredEntityData;

/**
* Storage object used within {@link StoredEntityData} to track the scaling state of an entity.
* This ensures that scale updates are only sent when the calculated scale actually changes.
*/
public final class EntityScaleData {

private boolean isBaby;
private float scale = 1.0f;

public boolean isBaby() {
return isBaby;
}

public void setBaby(boolean baby) {
this.isBaby = baby;
}

public float scale() {
return scale;
}

public void setScale(float scale) {
this.scale = scale;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* This file is part of ViaBackwards - https://github.com/ViaVersion/ViaBackwards
* Copyright (C) 2016-2026 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.viabackwards.api.entities;


import com.google.common.base.Preconditions;
import com.viaversion.viaversion.api.data.FullMappings;
import com.viaversion.viaversion.api.data.entity.StoredEntityData;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
import com.viaversion.viaversion.api.minecraft.entitydata.EntityData;
import com.viaversion.viaversion.api.protocol.Protocol;
import com.viaversion.viaversion.api.protocol.packet.ClientboundPacketType;
import com.viaversion.viaversion.api.protocol.packet.PacketWrapper;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.rewriter.EntityRewriter;
import com.viaversion.viaversion.rewriter.entitydata.EntityDataHandlerEvent;

/**
* A helper for injecting entity scaling on older clients.
* This helper listens for the baby entity data flag and sends an UPDATE_ATTRIBUTES packet
* to scale the entity, since older clients might not support the newer entity variants natively.
*/
public class EntityScaleHelper {

private final ClientboundPacketType updateAttributesPacket;
private final EntityRewriter<?, ?> rewriter;

/**
* Constructs a new entity scale helper.
*
* @param rewriter entity rewriter
* @param updateAttributesPacket UPDATE_ATTRIBUTES packet of the mapped protocol
* @param <CM> mapped clientbound packet type
*/
public <CM extends ClientboundPacketType, P extends Protocol<?, CM, ?, ?>> EntityScaleHelper(final EntityRewriter<?, P> rewriter, final CM updateAttributesPacket) {
this.rewriter = rewriter;
this.updateAttributesPacket = updateAttributesPacket;
}

/**
* Registers a scaling factor for a specific baby entity type.
*
* @param type entity type that requires scaling when it is a baby
* @param babyScaleFactor multiplier to apply to the minecraft:scale attribute when it is a baby
* @param babyIndex entity data index for the baby property in this specific protocol
*/
public void addBabyScale(final EntityType type, final float babyScaleFactor, final int babyIndex) {
rewriter.filter().type(type).index(babyIndex).handler(((event, data) -> trackAndSend(event, data, babyScaleFactor)));
}

/**
* Checks the entity data, tracks the scale state and sends an UPDATE_ATTRIBUTES packet if needed.
*/
public void trackAndSend(final EntityDataHandlerEvent event, final EntityData data, final float babyScaleFactor) {
if (event.trackedEntity() == null) {
return;
}

final StoredEntityData storedEntityData = event.trackedEntity().data();
EntityScaleData scaleData = storedEntityData.get(EntityScaleData.class);
if (scaleData == null) {
scaleData = new EntityScaleData();
storedEntityData.put(scaleData);
}

final boolean isBaby = data.value();
if (scaleData.isBaby() == isBaby) {
return;
}

scaleData.setBaby(isBaby);
scaleData.setScale(isBaby ? babyScaleFactor : 1.0f);

final FullMappings attributeMappings = rewriter.protocol().getMappingData().getAttributeMappings();
int attributeId = attributeMappings.mappedId("scale");
if (attributeId == -1) {
attributeId = attributeMappings.mappedId("generic.scale");
Preconditions.checkArgument(attributeId != -1);
}

final PacketWrapper attributesPacket = PacketWrapper.create(updateAttributesPacket, event.user());
attributesPacket.write(Types.VAR_INT, event.entityId());
attributesPacket.write(Types.VAR_INT, 1); // 1 attribute
attributesPacket.write(Types.VAR_INT, attributeId);
attributesPacket.write(Types.DOUBLE, (double) scaleData.scale());
attributesPacket.write(Types.VAR_INT, 0); // 0 modifiers
attributesPacket.send(rewriter.protocol().getClass());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import com.viaversion.nbt.tag.ListTag;
import com.viaversion.nbt.tag.Tag;
import com.viaversion.viabackwards.ViaBackwards;
import com.viaversion.viabackwards.api.entities.EntityScaleHelper;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.Protocol1_21_2To1_21;
import com.viaversion.viabackwards.protocol.v1_21_2to1_21.storage.PlayerStorage;
Expand Down Expand Up @@ -64,6 +65,7 @@ public final class EntityPacketRewriter1_21_2 extends EntityRewriter<Clientbound
private static final int REL_DELTA_Y = 6;
private static final int REL_DELTA_Z = 7;
private static final int REL_ROTATE_DELTA = 8;
private static final int WATER_CREATURE_BABY_INDEX = 16;
private boolean warned = ViaBackwards.getConfig().suppressEmulationWarnings();

public EntityPacketRewriter1_21_2(final Protocol1_21_2To1_21 protocol) {
Expand Down Expand Up @@ -643,9 +645,15 @@ protected void registerRewrites() {

filter().type(EntityTypes1_21_2.ABSTRACT_BOAT).addIndex(11); // Boat type
filter().type(EntityTypes1_21_2.SALMON).removeIndex(17); // Data type
filter().type(EntityTypes1_21_2.AGEABLE_WATER_CREATURE).removeIndex(16); // Baby

filter().type(EntityTypes1_21_2.ABSTRACT_ARROW).removeIndex(10); // In ground

final EntityScaleHelper scaleHelper = new EntityScaleHelper(this, ClientboundPackets1_21.UPDATE_ATTRIBUTES);
scaleHelper.addBabyScale(EntityTypes1_21_2.SQUID, 0.5f, WATER_CREATURE_BABY_INDEX);
scaleHelper.addBabyScale(EntityTypes1_21_2.GLOW_SQUID, 0.5f, WATER_CREATURE_BABY_INDEX);
scaleHelper.addBabyScale(EntityTypes1_21_2.DOLPHIN, 0.65f, WATER_CREATURE_BABY_INDEX);

filter().type(EntityTypes1_21_2.AGEABLE_WATER_CREATURE).removeIndex(WATER_CREATURE_BABY_INDEX);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/
package com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.rewriter;

import com.viaversion.viabackwards.api.entities.EntityScaleHelper;
import com.viaversion.viabackwards.api.rewriters.EntityRewriter;
import com.viaversion.viabackwards.protocol.v1_21_6to1_21_5.Protocol1_21_6To1_21_5;
import com.viaversion.viaversion.api.minecraft.entities.EntityType;
Expand Down Expand Up @@ -98,6 +99,11 @@ protected void registerRewrites() {
filter().type(EntityTypes1_21_6.HANGING_ENTITY).removeIndex(8); // Direction
filter().type(EntityTypes1_21_6.HAPPY_GHAST).cancel(17); // Leash holder
filter().type(EntityTypes1_21_6.HAPPY_GHAST).cancel(18); // Stays still

// Scale 0.2375 reduces the 4.0x4.0 Ghast hitbox to roughly 0.95x0.95 (approx 1x1) for the Ghastling
final EntityScaleHelper scaleHelper = new EntityScaleHelper(this, ClientboundPackets1_21_5.UPDATE_ATTRIBUTES);
scaleHelper.addBabyScale(EntityTypes1_21_6.HAPPY_GHAST, 0.2375f, 16);
filter().type(EntityTypes1_21_6.HAPPY_GHAST).cancel(16); // Charging for regular ghasts
}

@Override
Expand Down