1.16.5 How to identify/clear discounts from cured villagers?

Discussion in 'Spigot Plugin Development' started by Big_Scary, Aug 31, 2020.

  1. It's my understanding that cured villagers give huge discounts to the player who cured them. Is it possible to get that information from the API somewhere? I'm interested in both identifying which villagers have discounts for which players, and in some cases clearing those discounts if possible.
     
  2. From what I understood from the nms code every EntityVillager holds a Reputation object that can store a "gossp entry" for players which contain a ReputationType like
    Code (Text):
    MAJOR_NEGATIVE
    MINOR_NEGATIVE
    MINOR_POSITIVE
    MAJOR_POSITIVE
    TRADING
     
    Idk that was new to me but it is all desribed in the wiki pretty well. But I didn't find any API way to get that data.
     
  3. @MightyOne is correct. If you cure a villager and run a /data get entity ... on it, you'll see an entry called Gossips. In that one specific fork of spigot, you can actually get it through API (Villager#getReputations), but if you need to stay on spigot, you'll have to resort to NMS.

    (The following assumes you're on Spigot 1.16.2)
    While you can get the reputation just fine (entityVillager.fj();), the convenient field Map<UUID, Reputation.a> a that stores reputation per player is private, and the Reputation.a object that map stores is package private.

    Luckily, we can still make it work with the methods that are available to us without reflection:
    Code (Java):
    // I assume that you know the entity of which to modify the reputation
    CraftVillager craftVillager = (CraftVillager) entity;
    EntityVillager villager = craftVillager.getHandle();

    // Gets the current reputation entries of the villager
    Reputation reputation = villager.fj();

    UUID playerUniqueId = player.getUniqueId();

    // Minor and major positive reputation types can only be received through curing
    int minorPositive = reputation.a(playerUniqueId,
            reputationType -> reputationType == ReputationType.MINOR_POSITIVE);
    int majorPositive = reputation.a(playerUniqueId,
            reputationType -> reputationType == ReputationType.MAJOR_POSITIVE);

    // Having the current value at 0 means the player does not benefit from having cured the villager
    if (minorPositive == 0 && majorPositive == 0)
        return;

    // This method adds to the current reputation, so we negate the current one to set it to 0
    reputation.a(playerUniqueId, ReputationType.MINOR_POSITIVE, minorPositive * -1);
    reputation.a(playerUniqueId, ReputationType.MAJOR_POSITIVE, majorPositive * -1);
    Again, if you're not on 1.16.2, you might have to look up the correct method names yourself.
     
    • Funny Funny x 1
    • Informative Informative x 1
  4. Hey there! I was using this in 1.16.5 with:

    Code (Text):
    import net.minecraft.server.v1_16_R3.EntityVillager;
    import net.minecraft.server.v1_16_R3.Reputation;
    import net.minecraft.server.v1_16_R3.ReputationType;
    import org.bukkit.craftbukkit.v1_16_R3.entity.CraftVillager;
    Although the 1.17 snapshot doesn't support any sort of other imports.
    Is this still possible to remove the discount?