Mojira Archive
MC-114530

Horses can be ridden without saddle, pigs without carrot on a stick

The bug

Horses can be ridden even if they have no saddle equipped.

How to reproduce (vanilla)

The following uses the fact that because the steering is done client-side the forward movement is set client-side only as well. Since the method AbstractHorse.canBeSteered() does not test for the saddle (described below) the horse is moved with this set forward movement.

  1. Summon a horse
    /summon horse ~ ~ ~ {NoAI:1b,Tame:1b,SaddleItem:{id:"saddle",Count:1b}}
    
  2. Mount it
  3. Unequip the saddle
    → You will notice that the horse moves forward

How to reproduce (modded)

  1. Change the condition of the method net.minecraft.entity.passive.AbstractHorse.moveEntityWithHeading(float, float)
    // if (this.isBeingRidden() && this.canBeSteered() && this.isHorseSaddled())
    if (this.isBeingRidden() && this.canBeSteered() && (world.isRemote || this.isHorseSaddled()))
    
  2. Summon a horse
    /summon horse ~ ~ ~ {NoAI:1b,Tame:1b}
    
  3. Mount it and move

Note: To verify that the player and horse move server-side as well you can open the world to LAN and have a second player join or reproduce it on a server.

Code analysis

Based on 1.11.2 decompiled using MCP 9.35 rc1

The method net.minecraft.entity.passive.AbstractHorse.canBeSteered() should probably test if the horse has a saddle.
The method net.minecraft.network.NetHandlerPlayServer.processVehicleMove(CPacketVehicleMove) should then probably use net.minecraft.entity.Entity.canPassengerSteer() as additional condition.
This requires the method net.minecraft.entity.Entity.canPassengerSteer() to be adjusted:

public boolean canPassengerSteer()
{
    Entity entity = this.getControllingPassenger();
    /* Comment:
     * Replaced this, now some calls to this method require require an additional condition to only 
     * allow a client player to control the movement of an entity
     */
    // return entity instanceof EntityPlayer ? ((EntityPlayer)entity).isUser() : !this.world.isRemote;
    return !this.world.isRemote || (entity instanceof EntityPlayer && ((EntityPlayer) entity).isUser());
}

This adjustment causes some problems where controlling a ridden entity is only done client-side, therefor a new method called for example boolean shouldSteer() could be added which returns !world.isRemote and is overridden by EntityPlayer to return false and for EntityPlayerSP return true. Then all server-side calls to the old method Entity.canPassengerSteer() respectively EntityLiving.canPassengerSteer() can be replaced with entity.canPassengerSteer() && entity.getControllingPassenger().shouldSteer().

Note: Maybe add a null check to Entity.canPassengerSteer() in case it is called for entities with no (valid) passengers.

Fixed

Marcono1234

[Mojang] Gegy

2017-03-13, 04:10 PM

2022-03-24, 12:33 PM

2022-03-24, 12:33 PM

2

1

Confirmed

Normal

Mob behaviour, Player

horse, horse-saddle, player, ride

Minecraft 1.11.2 - Minecraft 1.13.2Minecraft 1.11.2, Minecraft 17w06a, Minecraft 1.12.2, Minecraft 17w50a, Minecraft 1.13.2

22w12a