minecraft-src/net/minecraft/world/item/component/ItemAttributeModifiers.java
2025-07-04 03:45:38 +03:00

124 lines
4.8 KiB
Java

package net.minecraft.world.item.component;
import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.List;
import java.util.Locale;
import java.util.function.BiConsumer;
import net.minecraft.Util;
import net.minecraft.core.Holder;
import net.minecraft.network.RegistryFriendlyByteBuf;
import net.minecraft.network.codec.ByteBufCodecs;
import net.minecraft.network.codec.StreamCodec;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.EquipmentSlotGroup;
import net.minecraft.world.entity.ai.attributes.Attribute;
import net.minecraft.world.entity.ai.attributes.AttributeModifier;
public record ItemAttributeModifiers(List<ItemAttributeModifiers.Entry> modifiers) {
public static final ItemAttributeModifiers EMPTY = new ItemAttributeModifiers(List.of());
public static final Codec<ItemAttributeModifiers> CODEC = ItemAttributeModifiers.Entry.CODEC
.listOf()
.xmap(ItemAttributeModifiers::new, ItemAttributeModifiers::modifiers);
public static final StreamCodec<RegistryFriendlyByteBuf, ItemAttributeModifiers> STREAM_CODEC = StreamCodec.composite(
ItemAttributeModifiers.Entry.STREAM_CODEC.apply(ByteBufCodecs.list()), ItemAttributeModifiers::modifiers, ItemAttributeModifiers::new
);
public static final DecimalFormat ATTRIBUTE_MODIFIER_FORMAT = Util.make(
new DecimalFormat("#.##"), decimalFormat -> decimalFormat.setDecimalFormatSymbols(DecimalFormatSymbols.getInstance(Locale.ROOT))
);
public static ItemAttributeModifiers.Builder builder() {
return new ItemAttributeModifiers.Builder();
}
public ItemAttributeModifiers withModifierAdded(Holder<Attribute> attribute, AttributeModifier modifier, EquipmentSlotGroup slot) {
ImmutableList.Builder<ItemAttributeModifiers.Entry> builder = ImmutableList.builderWithExpectedSize(this.modifiers.size() + 1);
for (ItemAttributeModifiers.Entry entry : this.modifiers) {
if (!entry.matches(attribute, modifier.id())) {
builder.add(entry);
}
}
builder.add(new ItemAttributeModifiers.Entry(attribute, modifier, slot));
return new ItemAttributeModifiers(builder.build());
}
public void forEach(EquipmentSlotGroup slotGroup, BiConsumer<Holder<Attribute>, AttributeModifier> action) {
for (ItemAttributeModifiers.Entry entry : this.modifiers) {
if (entry.slot.equals(slotGroup)) {
action.accept(entry.attribute, entry.modifier);
}
}
}
public void forEach(EquipmentSlot equipmentSlot, BiConsumer<Holder<Attribute>, AttributeModifier> action) {
for (ItemAttributeModifiers.Entry entry : this.modifiers) {
if (entry.slot.test(equipmentSlot)) {
action.accept(entry.attribute, entry.modifier);
}
}
}
public double compute(double baseValue, EquipmentSlot equipmentSlot) {
double d = baseValue;
for (ItemAttributeModifiers.Entry entry : this.modifiers) {
if (entry.slot.test(equipmentSlot)) {
double e = entry.modifier.amount();
d += switch (entry.modifier.operation()) {
case ADD_VALUE -> e;
case ADD_MULTIPLIED_BASE -> e * baseValue;
case ADD_MULTIPLIED_TOTAL -> e * d;
};
}
}
return d;
}
public static class Builder {
private final ImmutableList.Builder<ItemAttributeModifiers.Entry> entries = ImmutableList.builder();
Builder() {
}
public ItemAttributeModifiers.Builder add(Holder<Attribute> attribute, AttributeModifier modifier, EquipmentSlotGroup slot) {
this.entries.add(new ItemAttributeModifiers.Entry(attribute, modifier, slot));
return this;
}
public ItemAttributeModifiers build() {
return new ItemAttributeModifiers(this.entries.build());
}
}
public record Entry(Holder<Attribute> attribute, AttributeModifier modifier, EquipmentSlotGroup slot) {
public static final Codec<ItemAttributeModifiers.Entry> CODEC = RecordCodecBuilder.create(
instance -> instance.group(
Attribute.CODEC.fieldOf("type").forGetter(ItemAttributeModifiers.Entry::attribute),
AttributeModifier.MAP_CODEC.forGetter(ItemAttributeModifiers.Entry::modifier),
EquipmentSlotGroup.CODEC.optionalFieldOf("slot", EquipmentSlotGroup.ANY).forGetter(ItemAttributeModifiers.Entry::slot)
)
.apply(instance, ItemAttributeModifiers.Entry::new)
);
public static final StreamCodec<RegistryFriendlyByteBuf, ItemAttributeModifiers.Entry> STREAM_CODEC = StreamCodec.composite(
Attribute.STREAM_CODEC,
ItemAttributeModifiers.Entry::attribute,
AttributeModifier.STREAM_CODEC,
ItemAttributeModifiers.Entry::modifier,
EquipmentSlotGroup.STREAM_CODEC,
ItemAttributeModifiers.Entry::slot,
ItemAttributeModifiers.Entry::new
);
public boolean matches(Holder<Attribute> attribute, ResourceLocation id) {
return attribute.equals(this.attribute) && this.modifier.is(id);
}
}
}