package net.minecraft.world.entity.ai.attributes; import com.google.common.collect.Multimap; import com.mojang.logging.LogUtils; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import java.util.Collection; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import net.minecraft.Util; import net.minecraft.core.Holder; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.resources.ResourceLocation; import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; public class AttributeMap { private static final Logger LOGGER = LogUtils.getLogger(); private final Map, AttributeInstance> attributes = new Object2ObjectOpenHashMap<>(); private final Set attributesToSync = new ObjectOpenHashSet<>(); private final Set attributesToUpdate = new ObjectOpenHashSet<>(); private final AttributeSupplier supplier; public AttributeMap(AttributeSupplier supplier) { this.supplier = supplier; } private void onAttributeModified(AttributeInstance instance) { this.attributesToUpdate.add(instance); if (instance.getAttribute().value().isClientSyncable()) { this.attributesToSync.add(instance); } } public Set getAttributesToSync() { return this.attributesToSync; } public Set getAttributesToUpdate() { return this.attributesToUpdate; } public Collection getSyncableAttributes() { return (Collection)this.attributes .values() .stream() .filter(attributeInstance -> attributeInstance.getAttribute().value().isClientSyncable()) .collect(Collectors.toList()); } @Nullable public AttributeInstance getInstance(Holder attribute) { return (AttributeInstance)this.attributes.computeIfAbsent(attribute, holder -> this.supplier.createInstance(this::onAttributeModified, holder)); } public boolean hasAttribute(Holder attribute) { return this.attributes.get(attribute) != null || this.supplier.hasAttribute(attribute); } public boolean hasModifier(Holder attribute, ResourceLocation id) { AttributeInstance attributeInstance = (AttributeInstance)this.attributes.get(attribute); return attributeInstance != null ? attributeInstance.getModifier(id) != null : this.supplier.hasModifier(attribute, id); } public double getValue(Holder attribute) { AttributeInstance attributeInstance = (AttributeInstance)this.attributes.get(attribute); return attributeInstance != null ? attributeInstance.getValue() : this.supplier.getValue(attribute); } public double getBaseValue(Holder attribute) { AttributeInstance attributeInstance = (AttributeInstance)this.attributes.get(attribute); return attributeInstance != null ? attributeInstance.getBaseValue() : this.supplier.getBaseValue(attribute); } public double getModifierValue(Holder attribute, ResourceLocation id) { AttributeInstance attributeInstance = (AttributeInstance)this.attributes.get(attribute); return attributeInstance != null ? attributeInstance.getModifier(id).amount() : this.supplier.getModifierValue(attribute, id); } public void addTransientAttributeModifiers(Multimap, AttributeModifier> modifiers) { modifiers.forEach((holder, attributeModifier) -> { AttributeInstance attributeInstance = this.getInstance(holder); if (attributeInstance != null) { attributeInstance.removeModifier(attributeModifier.id()); attributeInstance.addTransientModifier(attributeModifier); } }); } public void removeAttributeModifiers(Multimap, AttributeModifier> modifiers) { modifiers.asMap().forEach((holder, collection) -> { AttributeInstance attributeInstance = (AttributeInstance)this.attributes.get(holder); if (attributeInstance != null) { collection.forEach(attributeModifier -> attributeInstance.removeModifier(attributeModifier.id())); } }); } public void assignAllValues(AttributeMap map) { map.attributes.values().forEach(attributeInstance -> { AttributeInstance attributeInstance2 = this.getInstance(attributeInstance.getAttribute()); if (attributeInstance2 != null) { attributeInstance2.replaceFrom(attributeInstance); } }); } public void assignBaseValues(AttributeMap map) { map.attributes.values().forEach(attributeInstance -> { AttributeInstance attributeInstance2 = this.getInstance(attributeInstance.getAttribute()); if (attributeInstance2 != null) { attributeInstance2.setBaseValue(attributeInstance.getBaseValue()); } }); } public ListTag save() { ListTag listTag = new ListTag(); for (AttributeInstance attributeInstance : this.attributes.values()) { listTag.add(attributeInstance.save()); } return listTag; } public void load(ListTag nbt) { for (int i = 0; i < nbt.size(); i++) { CompoundTag compoundTag = nbt.getCompound(i); String string = compoundTag.getString("id"); ResourceLocation resourceLocation = ResourceLocation.tryParse(string); if (resourceLocation != null) { Util.ifElse(BuiltInRegistries.ATTRIBUTE.getHolder(resourceLocation), reference -> { AttributeInstance attributeInstance = this.getInstance(reference); if (attributeInstance != null) { attributeInstance.load(compoundTag); } }, () -> LOGGER.warn("Ignoring unknown attribute '{}'", resourceLocation)); } else { LOGGER.warn("Ignoring malformed attribute '{}'", string); } } } }