Skip to content

Implement modular baby entity scaling (For feature request #1058)#1216

Open
mfishma wants to merge 4 commits intoViaVersion:masterfrom
mfishma:feature/scale-new-babies
Open

Implement modular baby entity scaling (For feature request #1058)#1216
mfishma wants to merge 4 commits intoViaVersion:masterfrom
mfishma:feature/scale-new-babies

Conversation

@mfishma
Copy link

@mfishma mfishma commented Feb 27, 2026

Scaling mob entities down to baby size

For feature request #1058

Overview

This PR introduces a new EntityScaleHelper API to provide a modular, instantiable way to physically scale baby mobs when backported to older clients. This should also future-proof baby mob scaling when backporting to clients that don't have native support for any new adult mob or its variants (e.g., 1.21.6 Happy Ghast (ghast) → 1.21.5, or 1.21.2 Squids → 1.20).

Changes made

  • New EntityScaleHelper: This can be instantiated per-protocol line (e.g., in EntityPacketRewriter1_21_6 and EntityPacketRewriter1_21_2.
  • Dynamic Baby Registration: Protocol rewriters can explicitly register which entities they care about and their desired scale factors using scaleHelper.addBabyScale(EntityType, factor).
  • Abstracted Injection: trackAndInject in EntityScaleHelper.java abstracts the logic of parsing the isBaby metadata index (16), calculating the scale, diffing it against EntityScaleData (stored in StoredEntityData), and forcefully injecting the UPDATE_ATTRIBUTES packet into the pipeline.
  • EntityScaleAttributeRewriter: A new extension of AttributeRewriter that intercepts server-sent attribute updates. This injects minecraft:scale changes and overrides them with our entity's tracked scale modifier. This cleans up manual interceptor blocks in 1.21.6 and protects squids/dolphins in 1.21.2 from server scale overrides.
  • Handles minecraft:generic.scale / minecraft:scale: The helper constructor takes the correct attribute key string so the injection logic natively handles the 1.21.2 attribute rename without hard-coding IDs.

Decisions

  • Why Force-Inject?: I noticed modern servers (like Paper 1.21.11) don't always dispatch an UPDATE_ATTRIBUTES packet when a baby mob spawns if the scale isn't modified on the server side. So we had to forcefully spoof the packet when the metadata dictates a scale drop.
  • Why Instantiable?: Rather than building a monolithic, static scale manager that tried to track all mobs across all versions, it's just instantiable. This minimizes rules to just the protocol version(s) that needs them.

Verification

Manual testing

  • ViaFabric 1.21.10: Verified the plugin loads correctly on the Fabric platform.
  • Paper 1.21.11 Server:
    • Connected with 1.21.5 client and verified Happy Ghast baby scaling.
    • Connected with 1.20.5 client and verified Ghast, Squids, & Dolphin scaling (using the attribute ID fix).
    • Used this summon command to verify with some perma-babies:
      /execute at <player> run summon minecraft:squid ~ ~ ~ {Age:-24000,AgeLocked:1b}
    • Confirmed the mobs correctly shrink on the client side without "popping" back to adult size upon further server updates.
Baby glow squid next to adult, from 1.20.5 Ghastlings scaled down, with hitboxes shown, from 1.20.5

@mfishma
Copy link
Author

mfishma commented Feb 27, 2026

(I renamed the branch, trying to keep the old PR, but couldn't)

@Kichura
Copy link
Member

Kichura commented Feb 27, 2026

Personal Opinion: This PR looks quite AI vibecoded (e.g: lots of comments everywhere and body of PR is oddly professionalish) and may not qualify for merge.

@mfishma
Copy link
Author

mfishma commented Feb 27, 2026

Fair enough, I'm also not a fan of over-confident "AI vibecoding" being dumped into repositories.

To be fully transparent: yeah, I used AI to help draft this PR. As a neuro-spicy developer myself, I used it to help organize my thoughts, summarize the changes for any reviewers, and save myself time. But I can see that it resulted in the code being way over-commented in an attempt to explain the changes. And the PR body came out feeling a bit weirdly corporate.

My goal was just to get this scaling logic out there for the Happy Ghast, learn more about how ViaBackwards works, and let the team assess its impact. It seemed more relevant given the recent focus on baby mobs, so there's a chance of more mobs with babies introduced soon. I totally understand that this touches some core Rewriter logic and will take time to review.

Once it's reviewed, lemme know which parts feel too noisy or over-explained, and I can take one more pass to strip out the excess comments and clean it up to better match the rest of the project's style.

scaleData.setScale(scale);

// Actively inject the packet so the client receives the scale update immediately
try {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need the try catch

*/
public class EntityScaleHelper {

private static final int BABY_INDEX = 16; // Standard Ageable "is_baby" index
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This often changes


private static final int BABY_INDEX = 16; // Standard Ageable "is_baby" index
private final Map<EntityType, Float> babyScales = new HashMap<>();
private final String scaleAttributeId;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just inline this

Comment on lines +111 to +112
int serverId = attributeMappings != null ? attributeMappings.id(scaleAttributeId) : -1;
int mappedId = serverId != -1 ? protocol.getMappingData().getNewAttributeId(serverId) : -1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just can directly call mappedId


// Fast lookup for scaling factor, negligible overhead if not present
float scale = 1.0f;
try {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No try catch

* @param data The current metadata piece being processed.
* @param protocol The protocol handling the translation, used for mapping lookups.
*/
public void trackAndInject(EntityDataHandlerEvent event, EntityData data, Protocol protocol) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attributes should be sent on spawn, not on entity data (both for performance reasons and because entities don't actually require entity data being sent)

scaleHelper.addBabyScale(EntityTypes1_21_2.DOLPHIN, 0.65f);

filter().handler((event, meta) -> {
scaleHelper.trackAndInject(event, meta, protocol);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should only be called for the ones that actually need it, not all

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants