--- a/net/minecraft/world/entity/ai/gossip/Reputation.java +++ b/net/minecraft/world/entity/ai/gossip/Reputation.java @@ -30,13 +30,27 @@ import net.minecraft.util.VisibleForDebug; import org.slf4j.Logger; +// CraftBukkit start +import net.minecraft.world.entity.npc.EntityVillager; +import org.bukkit.craftbukkit.entity.CraftVillager.CraftReputationType; +import org.bukkit.craftbukkit.event.CraftEventFactory; +import org.bukkit.entity.Villager; +import org.bukkit.event.entity.VillagerReputationChangeEvent; +// CraftBukkit end + public class Reputation { private static final Logger LOGGER = LogUtils.getLogger(); public static final int DISCARD_THRESHOLD = 2; private final Map gossips = Maps.newHashMap(); - public Reputation() {} + // CraftBukkit start - store reference to villager entity + private final EntityVillager villager; + + public Reputation(EntityVillager villager) { + this.villager = villager; + } + // CraftBukkit end @VisibleForDebug public Map> getGossipEntries() { @@ -51,15 +65,17 @@ } public void decay() { - Iterator iterator = this.gossips.values().iterator(); + Iterator> iterator = this.gossips.entrySet().iterator(); // CraftBukkit - iterate over entries instead of values to access entity UUID while (iterator.hasNext()) { - Reputation.a reputation_a = (Reputation.a) iterator.next(); + // CraftBukkit start - pass villager and entity UUID to decay method + Map.Entry reputation_a = iterator.next(); - reputation_a.decay(); - if (reputation_a.isEmpty()) { + reputation_a.getValue().decay(villager, reputation_a.getKey()); + if (reputation_a.getValue().isEmpty()) { iterator.remove(); } + // CraftBukkit end } } @@ -112,16 +128,27 @@ int j = reputation_b.value - reputation_b.type.decayPerTransfer; if (j >= 2) { - this.getOrCreate(reputation_b.target).entries.mergeInt(reputation_b.type, j, Reputation::mergeValuesForTransfer); + // CraftBukkit start - redirect to a method which fires an event before setting value + this.set(reputation_b.target, reputation_b.type, Reputation.mergeValuesForTransfer(getReputation(reputation_b.target, Predicate.isEqual(reputation_b.type), false), j), Villager.ReputationEvent.GOSSIP); + //this.getOrCreate(reputation_b.target).entries.mergeInt(reputation_b.type, j, Reputation::mergeValuesForTransfer); + // CraftBukkit end } }); } public int getReputation(UUID uuid, Predicate predicate) { + // CraftBukkit start - add getReputation overload with additional parameter + return getReputation(uuid, predicate, true); + } + + public int getReputation(UUID uuid, Predicate predicate, boolean weighted) { + // CraftBukkit end Reputation.a reputation_a = (Reputation.a) this.gossips.get(uuid); - return reputation_a != null ? reputation_a.weightedValue(predicate) : 0; + // CraftBukkit start - handle weighted parameter + return reputation_a != null ? (weighted ? reputation_a.weightedValue(predicate) : reputation_a.unweightedValue(predicate)) : 0; + // CraftBukkit end } public long getCountForType(ReputationType reputationtype, DoublePredicate doublepredicate) { @@ -131,27 +158,58 @@ } public void add(UUID uuid, ReputationType reputationtype, int i) { + // CraftBukkit start - add change reason parameter + add(uuid, reputationtype, i, Villager.ReputationEvent.UNSPECIFIED); + } + + public void add(UUID uuid, ReputationType reputationtype, int i, Villager.ReputationEvent changeReason) { + // CraftBukkit end Reputation.a reputation_a = this.getOrCreate(uuid); + int oldValue = reputation_a.entries.getInt(reputationtype); // CraftBukkit - store old value reputation_a.entries.mergeInt(reputationtype, i, (j, k) -> { return this.mergeValuesForAddition(reputationtype, j, k); }); - reputation_a.makeSureValueIsntTooLowOrTooHigh(reputationtype); + // CraftBukkit start - fire reputation change event + int newValue = reputation_a.entries.getInt(reputationtype); + newValue = Math.max(0, Math.min(newValue, reputationtype.max)); + reputation_a.entries.replace(reputationtype, oldValue); // restore old value until the event completed processing + VillagerReputationChangeEvent event = CraftEventFactory.callVillagerReputationChangeEvent((Villager) villager.getBukkitEntity(), uuid, changeReason, CraftReputationType.minecraftToBukkit(reputationtype), oldValue, newValue, reputationtype.max); + if (!event.isCancelled()) { + reputation_a.entries.replace(reputationtype, event.getNewValue()); + reputation_a.makeSureValueIsntTooLowOrTooHigh(reputationtype); + } + // CraftBukkit end if (reputation_a.isEmpty()) { this.gossips.remove(uuid); } } - public void remove(UUID uuid, ReputationType reputationtype, int i) { - this.add(uuid, reputationtype, -i); + // CraftBukkit start + public void set(UUID uuid, ReputationType reputationType, int i, Villager.ReputationEvent changeReason) { + int addAmount = i - getReputation(uuid, Predicate.isEqual(reputationType), false); + if (addAmount == 0) { + return; + } + this.add(uuid, reputationType, addAmount, changeReason); } + // CraftBukkit end - public void remove(UUID uuid, ReputationType reputationtype) { + // CraftBukkit start - add change reason parameter + public void remove(UUID uuid, ReputationType reputationtype, int i, Villager.ReputationEvent changeReason) { + this.add(uuid, reputationtype, -i, changeReason); + } + // CraftBukkit end + + public void remove(UUID uuid, ReputationType reputationtype, Villager.ReputationEvent changeReason) { // CraftBukkit - add change reason parameter Reputation.a reputation_a = (Reputation.a) this.gossips.get(uuid); if (reputation_a != null) { - reputation_a.remove(reputationtype); + // CraftBukkit start - redirect - set to 0 instead + set(uuid, reputationtype, 0, changeReason); + //reputation_a.remove(reputationtype); + // CraftBukkit end if (reputation_a.isEmpty()) { this.gossips.remove(uuid); } @@ -159,7 +217,16 @@ } - public void remove(ReputationType reputationtype) { + public void remove(ReputationType reputationtype, Villager.ReputationEvent changeReason) { // CraftBukkit - add change reason parameter + // CraftBukkit start - replace the logic to call the other remove instead + Set uuids = Sets.newHashSet(this.gossips.keySet()); + for (UUID uuid : uuids) { + remove(uuid, reputationtype, changeReason); + } + if (true) { + return; + } + // CraftBukkit end Iterator iterator = this.gossips.values().iterator(); while (iterator.hasNext()) { @@ -174,7 +241,7 @@ } public T store(DynamicOps dynamicops) { - Optional optional = Reputation.b.LIST_CODEC.encodeStart(dynamicops, this.unpack().toList()).resultOrPartial((s) -> { + Optional optional = Reputation.b.LIST_CODEC.encodeStart(dynamicops, this.unpack().toList()).resultOrPartial((s) -> { // CraftBukkit - missing generic parameter after decompile Reputation.LOGGER.warn("Failed to serialize gossips: {}", s); }); @@ -186,7 +253,7 @@ Reputation.b.LIST_CODEC.decode(dynamic).resultOrPartial((s) -> { Reputation.LOGGER.warn("Failed to deserialize gossips: {}", s); }).stream().flatMap((pair) -> { - return ((List) pair.getFirst()).stream(); + return ((List) pair.getFirst()).stream(); // CraftBukkit - missing generic parameter after decompile }).forEach((reputation_b) -> { this.getOrCreate(reputation_b.target).entries.put(reputation_b.type, reputation_b.value); }); @@ -216,18 +283,36 @@ }).sum(); } + // CraftBukkit start + public int unweightedValue(Predicate predicate) { + return this.entries.object2IntEntrySet().stream().filter((entry) -> { + return predicate.test((ReputationType) entry.getKey()); + }).mapToInt((entry) -> { + return entry.getIntValue(); + }).sum(); + } + // CraftBukkit end + public Stream unpack(UUID uuid) { return this.entries.object2IntEntrySet().stream().map((entry) -> { return new Reputation.b(uuid, (ReputationType) entry.getKey(), entry.getIntValue()); }); } - public void decay() { + public void decay(EntityVillager villager, UUID uuid) { // CraftBukkit - add villager and entity uuid parameters ObjectIterator> objectiterator = this.entries.object2IntEntrySet().iterator(); while (objectiterator.hasNext()) { Entry entry = (Entry) objectiterator.next(); int i = entry.getIntValue() - ((ReputationType) entry.getKey()).decayPerDay; + // CraftBukkit start - fire event + VillagerReputationChangeEvent event = CraftEventFactory.callVillagerReputationChangeEvent((Villager) villager.getBukkitEntity(), uuid, Villager.ReputationEvent.DECAY, CraftReputationType.minecraftToBukkit(entry.getKey()), entry.getIntValue(), i, entry.getKey().max); + if (event.isCancelled()) { + continue; + } else { + i = event.getNewValue(); + } + // CraftBukkit end if (i < 2) { objectiterator.remove();