mojira.dev
MC-247647

Cured villagers don't give discounts if the player that cured it logs off before the conversion

If a villager starts curing while the player who started it, is offline. The player doesnt get a discount. This is due to EntityGetter.getPlayerByUUID returning NULL, since it only searches online players.

 

  1. Get Zombie Villager in a multiplayer world

  2. Start curing it like normal

  3. Disconnect

  4. Wait for curing to finish

  5. Reconnect

  6. Villager cured, but no discount received

 

Fix: If the No Online player can be found. Search through offline players aswell. Since in theory this should never be Null, as curing can only be started by a player

Comments 1

Code Analysis (Mojang Mappings 1.18.1)
ZombieVillager.java

private void finishConversion(ServerLevel level) {
    ...
    if (this.conversionStarter != null) {
        Player player = level.getPlayerByUUID(this.conversionStarter);
        if (player instanceof ServerPlayer) {
            CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer)player, this, villager);
            level.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, player, villager);
        }
    }
    ...
}

EntityGetter.java

@Nullable
default Player getPlayerByUUID(UUID uuid) {
    for(int c = 0; c < this.players().size(); ++c) {
        Player player = this.players().get(c);
        if (uuid.equals(player.getUUID())) {
            return player;
        }
    }
    return null;
}

VillagerEntity.java

@Override
public void onReputationEventFrom(ReputationEventType type, Entity entity) {
    if (type == ReputationEventType.ZOMBIE_VILLAGER_CURED) {
        this.gossips.add(entity.getUUID(), GossipType.MAJOR_POSITIVE, 20);
        this.gossips.add(entity.getUUID(), GossipType.MINOR_POSITIVE, 25);
    } else if (type == ReputationEventType.TRADE) {
        this.gossips.add(entity.getUUID(), GossipType.TRADING, 2);
    } else if (type == ReputationEventType.VILLAGER_HURT) {
        this.gossips.add(entity.getUUID(), GossipType.MINOR_NEGATIVE, 25);
    } else if (type == ReputationEventType.VILLAGER_KILLED) {
        this.gossips.add(entity.getUUID(), GossipType.MAJOR_NEGATIVE, 25);
    }
}

As you can see VillagerEntity.onReputationEventFrom() only uses the UUID from the entities. So changing that argument to be a UUID would allow you to change the code inside of ZombieVillager.java to this:

private void finishConversion(ServerLevel level) {
    ...
    if (this.conversionStarter != null) {
        Player player = level.getPlayerByUUID(this.conversionStarter);
        level.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, this.conversionStarter, villager);
        if (player instanceof ServerPlayer) {
            CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer)player, this, villager);
        }
    }
    ...
}

Which would allow offline players to be saved without much work.

Nothing else uses these calls 😉

Eirik Skarding

(Unassigned)

Community Consensus

Platform

Normal

Village system

1.18.1

Retrieved