package net.minecraft.world.entity.ai.gossip; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import com.mojang.serialization.codecs.RecordCodecBuilder.Instance; import it.unimi.dsi.fastutil.objects.Object2IntMap; import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIterator; import it.unimi.dsi.fastutil.objects.Object2IntMap.Entry; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.function.DoublePredicate; import java.util.function.Predicate; import java.util.stream.Stream; import net.minecraft.core.UUIDUtil; import net.minecraft.util.ExtraCodecs; import net.minecraft.util.RandomSource; import net.minecraft.util.VisibleForDebug; public class GossipContainer { public static final Codec CODEC = GossipContainer.GossipEntry.CODEC .listOf() .xmap(GossipContainer::new, p_390638_ -> p_390638_.unpack().toList()); public static final int DISCARD_THRESHOLD = 2; private final Map gossips = new HashMap<>(); public GossipContainer() { } private GossipContainer(List p_397266_) { p_397266_.forEach(p_26162_ -> this.getOrCreate(p_26162_.target).entries.put(p_26162_.type, p_26162_.value)); } @VisibleForDebug public Map> getGossipEntries() { Map> map = Maps.newHashMap(); this.gossips.keySet().forEach(p_148167_ -> { GossipContainer.EntityGossips gossipcontainer$entitygossips = this.gossips.get(p_148167_); map.put(p_148167_, gossipcontainer$entitygossips.entries); }); return map; } public void decay() { Iterator iterator = this.gossips.values().iterator(); while (iterator.hasNext()) { GossipContainer.EntityGossips gossipcontainer$entitygossips = iterator.next(); gossipcontainer$entitygossips.decay(); if (gossipcontainer$entitygossips.isEmpty()) { iterator.remove(); } } } private Stream unpack() { return this.gossips.entrySet().stream().flatMap(p_26185_ -> p_26185_.getValue().unpack(p_26185_.getKey())); } private Collection selectGossipsForTransfer(RandomSource p_217760_, int p_217761_) { List list = this.unpack().toList(); if (list.isEmpty()) { return Collections.emptyList(); } else { int[] aint = new int[list.size()]; int i = 0; for (int j = 0; j < list.size(); j++) { GossipContainer.GossipEntry gossipcontainer$gossipentry = list.get(j); i += Math.abs(gossipcontainer$gossipentry.weightedValue()); aint[j] = i - 1; } Set set = Sets.newIdentityHashSet(); for (int i1 = 0; i1 < p_217761_; i1++) { int k = p_217760_.nextInt(i); int l = Arrays.binarySearch(aint, k); set.add(list.get(l < 0 ? -l - 1 : l)); } return set; } } private GossipContainer.EntityGossips getOrCreate(UUID p_26190_) { return this.gossips.computeIfAbsent(p_26190_, p_26202_ -> new GossipContainer.EntityGossips()); } public void transferFrom(GossipContainer p_217763_, RandomSource p_217764_, int p_217765_) { Collection collection = p_217763_.selectGossipsForTransfer(p_217764_, p_217765_); collection.forEach(p_26200_ -> { int i = p_26200_.value - p_26200_.type.decayPerTransfer; if (i >= 2) { this.getOrCreate(p_26200_.target).entries.mergeInt(p_26200_.type, i, GossipContainer::mergeValuesForTransfer); } }); } public int getReputation(UUID p_26196_, Predicate p_26197_) { GossipContainer.EntityGossips gossipcontainer$entitygossips = this.gossips.get(p_26196_); return gossipcontainer$entitygossips != null ? gossipcontainer$entitygossips.weightedValue(p_26197_) : 0; } public long getCountForType(GossipType p_148163_, DoublePredicate p_148164_) { return this.gossips.values().stream().filter(p_148174_ -> p_148164_.test(p_148174_.entries.getOrDefault(p_148163_, 0) * p_148163_.weight)).count(); } public void add(UUID p_26192_, GossipType p_26193_, int p_26194_) { GossipContainer.EntityGossips gossipcontainer$entitygossips = this.getOrCreate(p_26192_); gossipcontainer$entitygossips.entries.mergeInt(p_26193_, p_26194_, (p_186096_, p_186097_) -> this.mergeValuesForAddition(p_26193_, p_186096_, p_186097_)); gossipcontainer$entitygossips.makeSureValueIsntTooLowOrTooHigh(p_26193_); if (gossipcontainer$entitygossips.isEmpty()) { this.gossips.remove(p_26192_); } } public void remove(UUID p_148176_, GossipType p_148177_, int p_148178_) { this.add(p_148176_, p_148177_, -p_148178_); } public void remove(UUID p_148169_, GossipType p_148170_) { GossipContainer.EntityGossips gossipcontainer$entitygossips = this.gossips.get(p_148169_); if (gossipcontainer$entitygossips != null) { gossipcontainer$entitygossips.remove(p_148170_); if (gossipcontainer$entitygossips.isEmpty()) { this.gossips.remove(p_148169_); } } } public void remove(GossipType p_148161_) { Iterator iterator = this.gossips.values().iterator(); while (iterator.hasNext()) { GossipContainer.EntityGossips gossipcontainer$entitygossips = iterator.next(); gossipcontainer$entitygossips.remove(p_148161_); if (gossipcontainer$entitygossips.isEmpty()) { iterator.remove(); } } } public void clear() { this.gossips.clear(); } public void putAll(GossipContainer p_391716_) { p_391716_.gossips.forEach((p_390636_, p_390637_) -> this.getOrCreate(p_390636_).entries.putAll(p_390637_.entries)); } private static int mergeValuesForTransfer(int p_26159_, int p_26160_) { return Math.max(p_26159_, p_26160_); } private int mergeValuesForAddition(GossipType p_26168_, int p_26169_, int p_26170_) { int i = p_26169_ + p_26170_; return i > p_26168_.max ? Math.max(p_26168_.max, p_26169_) : i; } public GossipContainer copy() { GossipContainer gossipcontainer = new GossipContainer(); gossipcontainer.putAll(this); return gossipcontainer; } static class EntityGossips { final Object2IntMap entries = new Object2IntOpenHashMap<>(); public int weightedValue(Predicate p_26221_) { return this.entries .object2IntEntrySet() .stream() .filter(p_26224_ -> p_26221_.test(p_26224_.getKey())) .mapToInt(p_26214_ -> p_26214_.getIntValue() * p_26214_.getKey().weight) .sum(); } public Stream unpack(UUID p_26216_) { return this.entries .object2IntEntrySet() .stream() .map(p_26219_ -> new GossipContainer.GossipEntry(p_26216_, p_26219_.getKey(), p_26219_.getIntValue())); } public void decay() { ObjectIterator> objectiterator = this.entries.object2IntEntrySet().iterator(); while (objectiterator.hasNext()) { Entry entry = objectiterator.next(); int i = entry.getIntValue() - entry.getKey().decayPerDay; if (i < 2) { objectiterator.remove(); } else { entry.setValue(i); } } } public boolean isEmpty() { return this.entries.isEmpty(); } public void makeSureValueIsntTooLowOrTooHigh(GossipType p_26212_) { int i = this.entries.getInt(p_26212_); if (i > p_26212_.max) { this.entries.put(p_26212_, p_26212_.max); } if (i < 2) { this.remove(p_26212_); } } public void remove(GossipType p_26227_) { this.entries.removeInt(p_26227_); } } record GossipEntry(UUID target, GossipType type, int value) { public static final Codec CODEC = RecordCodecBuilder.create( p_263007_ -> p_263007_.group( UUIDUtil.CODEC.fieldOf("Target").forGetter(GossipContainer.GossipEntry::target), GossipType.CODEC.fieldOf("Type").forGetter(GossipContainer.GossipEntry::type), ExtraCodecs.POSITIVE_INT.fieldOf("Value").forGetter(GossipContainer.GossipEntry::value) ) .apply(p_263007_, GossipContainer.GossipEntry::new) ); public int weightedValue() { return this.value * this.type.weight; } } }