493 lines
29 KiB
Java
493 lines
29 KiB
Java
/*
|
|
* Decompiled with CFR 0.152.
|
|
*
|
|
* Could not load the following classes:
|
|
* com.google.common.collect.Maps
|
|
* com.mojang.datafixers.kinds.App
|
|
* com.mojang.datafixers.kinds.Applicative
|
|
* com.mojang.serialization.Codec
|
|
* com.mojang.serialization.MapCodec
|
|
* com.mojang.serialization.codecs.RecordCodecBuilder
|
|
* it.unimi.dsi.fastutil.objects.ObjectArraySet
|
|
* org.apache.commons.lang3.mutable.MutableFloat
|
|
*/
|
|
package net.minecraft.world.item.enchantment;
|
|
|
|
import com.google.common.collect.Maps;
|
|
import com.mojang.datafixers.kinds.App;
|
|
import com.mojang.datafixers.kinds.Applicative;
|
|
import com.mojang.serialization.Codec;
|
|
import com.mojang.serialization.MapCodec;
|
|
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
|
import it.unimi.dsi.fastutil.objects.ObjectArraySet;
|
|
import java.util.ArrayList;
|
|
import java.util.EnumMap;
|
|
import java.util.HashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.Set;
|
|
import java.util.function.Consumer;
|
|
import net.minecraft.ChatFormatting;
|
|
import net.minecraft.core.Holder;
|
|
import net.minecraft.core.HolderSet;
|
|
import net.minecraft.core.RegistryCodecs;
|
|
import net.minecraft.core.component.DataComponentMap;
|
|
import net.minecraft.core.component.DataComponentType;
|
|
import net.minecraft.core.registries.Registries;
|
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
|
import net.minecraft.network.chat.CommonComponents;
|
|
import net.minecraft.network.chat.Component;
|
|
import net.minecraft.network.chat.ComponentSerialization;
|
|
import net.minecraft.network.chat.ComponentUtils;
|
|
import net.minecraft.network.chat.MutableComponent;
|
|
import net.minecraft.network.chat.Style;
|
|
import net.minecraft.network.codec.ByteBufCodecs;
|
|
import net.minecraft.network.codec.StreamCodec;
|
|
import net.minecraft.resources.Identifier;
|
|
import net.minecraft.resources.RegistryFixedCodec;
|
|
import net.minecraft.server.level.ServerLevel;
|
|
import net.minecraft.tags.EnchantmentTags;
|
|
import net.minecraft.util.ExtraCodecs;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.util.Unit;
|
|
import net.minecraft.util.Util;
|
|
import net.minecraft.world.damagesource.DamageSource;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EquipmentSlot;
|
|
import net.minecraft.world.entity.EquipmentSlotGroup;
|
|
import net.minecraft.world.entity.LivingEntity;
|
|
import net.minecraft.world.item.Item;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.item.enchantment.ConditionalEffect;
|
|
import net.minecraft.world.item.enchantment.EnchantedItemInUse;
|
|
import net.minecraft.world.item.enchantment.EnchantmentEffectComponents;
|
|
import net.minecraft.world.item.enchantment.EnchantmentTarget;
|
|
import net.minecraft.world.item.enchantment.TargetedConditionalEffect;
|
|
import net.minecraft.world.item.enchantment.effects.EnchantmentAttributeEffect;
|
|
import net.minecraft.world.item.enchantment.effects.EnchantmentEntityEffect;
|
|
import net.minecraft.world.item.enchantment.effects.EnchantmentLocationBasedEffect;
|
|
import net.minecraft.world.item.enchantment.effects.EnchantmentValueEffect;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.storage.loot.LootContext;
|
|
import net.minecraft.world.level.storage.loot.LootParams;
|
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets;
|
|
import net.minecraft.world.level.storage.loot.parameters.LootContextParams;
|
|
import net.minecraft.world.level.storage.loot.predicates.LootItemCondition;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.apache.commons.lang3.mutable.MutableFloat;
|
|
|
|
public record Enchantment(Component description, EnchantmentDefinition definition, HolderSet<Enchantment> exclusiveSet, DataComponentMap effects) {
|
|
public static final int MAX_LEVEL = 255;
|
|
public static final Codec<Enchantment> DIRECT_CODEC = RecordCodecBuilder.create(i -> i.group((App)ComponentSerialization.CODEC.fieldOf("description").forGetter(Enchantment::description), (App)EnchantmentDefinition.CODEC.forGetter(Enchantment::definition), (App)RegistryCodecs.homogeneousList(Registries.ENCHANTMENT).optionalFieldOf("exclusive_set", HolderSet.direct(new Holder[0])).forGetter(Enchantment::exclusiveSet), (App)EnchantmentEffectComponents.CODEC.optionalFieldOf("effects", (Object)DataComponentMap.EMPTY).forGetter(Enchantment::effects)).apply((Applicative)i, Enchantment::new));
|
|
public static final Codec<Holder<Enchantment>> CODEC = RegistryFixedCodec.create(Registries.ENCHANTMENT);
|
|
public static final StreamCodec<RegistryFriendlyByteBuf, Holder<Enchantment>> STREAM_CODEC = ByteBufCodecs.holderRegistry(Registries.ENCHANTMENT);
|
|
|
|
public static Cost constantCost(int base) {
|
|
return new Cost(base, 0);
|
|
}
|
|
|
|
public static Cost dynamicCost(int base, int perLevel) {
|
|
return new Cost(base, perLevel);
|
|
}
|
|
|
|
public static EnchantmentDefinition definition(HolderSet<Item> supportedItems, HolderSet<Item> primaryItems, int weight, int maxLevel, Cost minCost, Cost maxCost, int anvilCost, EquipmentSlotGroup ... slots) {
|
|
return new EnchantmentDefinition(supportedItems, Optional.of(primaryItems), weight, maxLevel, minCost, maxCost, anvilCost, List.of(slots));
|
|
}
|
|
|
|
public static EnchantmentDefinition definition(HolderSet<Item> supportedItems, int weight, int maxLevel, Cost minCost, Cost maxCost, int anvilCost, EquipmentSlotGroup ... slots) {
|
|
return new EnchantmentDefinition(supportedItems, Optional.empty(), weight, maxLevel, minCost, maxCost, anvilCost, List.of(slots));
|
|
}
|
|
|
|
public Map<EquipmentSlot, ItemStack> getSlotItems(LivingEntity entity) {
|
|
EnumMap itemStacks = Maps.newEnumMap(EquipmentSlot.class);
|
|
for (EquipmentSlot slot : EquipmentSlot.VALUES) {
|
|
ItemStack itemStack;
|
|
if (!this.matchingSlot(slot) || (itemStack = entity.getItemBySlot(slot)).isEmpty()) continue;
|
|
itemStacks.put(slot, itemStack);
|
|
}
|
|
return itemStacks;
|
|
}
|
|
|
|
public HolderSet<Item> getSupportedItems() {
|
|
return this.definition.supportedItems();
|
|
}
|
|
|
|
public boolean matchingSlot(EquipmentSlot slot) {
|
|
return this.definition.slots().stream().anyMatch(group -> group.test(slot));
|
|
}
|
|
|
|
public boolean isPrimaryItem(ItemStack item) {
|
|
return this.isSupportedItem(item) && (this.definition.primaryItems.isEmpty() || item.is(this.definition.primaryItems.get()));
|
|
}
|
|
|
|
public boolean isSupportedItem(ItemStack item) {
|
|
return item.is(this.definition.supportedItems);
|
|
}
|
|
|
|
public int getWeight() {
|
|
return this.definition.weight();
|
|
}
|
|
|
|
public int getAnvilCost() {
|
|
return this.definition.anvilCost();
|
|
}
|
|
|
|
public int getMinLevel() {
|
|
return 1;
|
|
}
|
|
|
|
public int getMaxLevel() {
|
|
return this.definition.maxLevel();
|
|
}
|
|
|
|
public int getMinCost(int level) {
|
|
return this.definition.minCost().calculate(level);
|
|
}
|
|
|
|
public int getMaxCost(int level) {
|
|
return this.definition.maxCost().calculate(level);
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return "Enchantment " + this.description.getString();
|
|
}
|
|
|
|
public static boolean areCompatible(Holder<Enchantment> enchantment, Holder<Enchantment> other) {
|
|
return !enchantment.equals(other) && !enchantment.value().exclusiveSet.contains(other) && !other.value().exclusiveSet.contains(enchantment);
|
|
}
|
|
|
|
public static Component getFullname(Holder<Enchantment> enchantment, int level) {
|
|
MutableComponent result = enchantment.value().description.copy();
|
|
result = enchantment.is(EnchantmentTags.CURSE) ? ComponentUtils.mergeStyles(result, Style.EMPTY.withColor(ChatFormatting.RED)) : ComponentUtils.mergeStyles(result, Style.EMPTY.withColor(ChatFormatting.GRAY));
|
|
if (level != 1 || enchantment.value().getMaxLevel() != 1) {
|
|
result.append(CommonComponents.SPACE).append(Component.translatable("enchantment.level." + level));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
public boolean canEnchant(ItemStack itemStack) {
|
|
return this.definition.supportedItems().contains(itemStack.getItemHolder());
|
|
}
|
|
|
|
public <T> List<T> getEffects(DataComponentType<List<T>> type) {
|
|
return this.effects.getOrDefault(type, List.of());
|
|
}
|
|
|
|
public boolean isImmuneToDamage(ServerLevel serverLevel, int enchantmentLevel, Entity victim, DamageSource source) {
|
|
LootContext context = Enchantment.damageContext(serverLevel, enchantmentLevel, victim, source);
|
|
for (ConditionalEffect filteredEffect : this.getEffects(EnchantmentEffectComponents.DAMAGE_IMMUNITY)) {
|
|
if (!filteredEffect.matches(context)) continue;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public void modifyDamageProtection(ServerLevel serverLevel, int enchantmentLevel, ItemStack item, Entity victim, DamageSource source, MutableFloat protection) {
|
|
LootContext context = Enchantment.damageContext(serverLevel, enchantmentLevel, victim, source);
|
|
for (ConditionalEffect conditionalEffect : this.getEffects(EnchantmentEffectComponents.DAMAGE_PROTECTION)) {
|
|
if (!conditionalEffect.matches(context)) continue;
|
|
protection.setValue(((EnchantmentValueEffect)conditionalEffect.effect()).process(enchantmentLevel, victim.getRandom(), protection.floatValue()));
|
|
}
|
|
}
|
|
|
|
public void modifyDurabilityChange(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, MutableFloat change) {
|
|
this.modifyItemFilteredCount(EnchantmentEffectComponents.ITEM_DAMAGE, serverLevel, enchantmentLevel, itemStack, change);
|
|
}
|
|
|
|
public void modifyAmmoCount(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, MutableFloat change) {
|
|
this.modifyItemFilteredCount(EnchantmentEffectComponents.AMMO_USE, serverLevel, enchantmentLevel, itemStack, change);
|
|
}
|
|
|
|
public void modifyPiercingCount(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, MutableFloat count) {
|
|
this.modifyItemFilteredCount(EnchantmentEffectComponents.PROJECTILE_PIERCING, serverLevel, enchantmentLevel, itemStack, count);
|
|
}
|
|
|
|
public void modifyBlockExperience(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, MutableFloat count) {
|
|
this.modifyItemFilteredCount(EnchantmentEffectComponents.BLOCK_EXPERIENCE, serverLevel, enchantmentLevel, itemStack, count);
|
|
}
|
|
|
|
public void modifyMobExperience(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity killer, MutableFloat experience) {
|
|
this.modifyEntityFilteredValue(EnchantmentEffectComponents.MOB_EXPERIENCE, serverLevel, enchantmentLevel, itemStack, killer, experience);
|
|
}
|
|
|
|
public void modifyDurabilityToRepairFromXp(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, MutableFloat change) {
|
|
this.modifyItemFilteredCount(EnchantmentEffectComponents.REPAIR_WITH_XP, serverLevel, enchantmentLevel, itemStack, change);
|
|
}
|
|
|
|
public void modifyTridentReturnToOwnerAcceleration(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity trident, MutableFloat count) {
|
|
this.modifyEntityFilteredValue(EnchantmentEffectComponents.TRIDENT_RETURN_ACCELERATION, serverLevel, enchantmentLevel, itemStack, trident, count);
|
|
}
|
|
|
|
public void modifyTridentSpinAttackStrength(RandomSource random, int enchantmentLevel, MutableFloat strength) {
|
|
this.modifyUnfilteredValue(EnchantmentEffectComponents.TRIDENT_SPIN_ATTACK_STRENGTH, random, enchantmentLevel, strength);
|
|
}
|
|
|
|
public void modifyFishingTimeReduction(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity fisher, MutableFloat timeReduction) {
|
|
this.modifyEntityFilteredValue(EnchantmentEffectComponents.FISHING_TIME_REDUCTION, serverLevel, enchantmentLevel, itemStack, fisher, timeReduction);
|
|
}
|
|
|
|
public void modifyFishingLuckBonus(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity fisher, MutableFloat luck) {
|
|
this.modifyEntityFilteredValue(EnchantmentEffectComponents.FISHING_LUCK_BONUS, serverLevel, enchantmentLevel, itemStack, fisher, luck);
|
|
}
|
|
|
|
public void modifyDamage(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity victim, DamageSource damageSource, MutableFloat amount) {
|
|
this.modifyDamageFilteredValue(EnchantmentEffectComponents.DAMAGE, serverLevel, enchantmentLevel, itemStack, victim, damageSource, amount);
|
|
}
|
|
|
|
public void modifyFallBasedDamage(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity victim, DamageSource damageSource, MutableFloat amount) {
|
|
this.modifyDamageFilteredValue(EnchantmentEffectComponents.SMASH_DAMAGE_PER_FALLEN_BLOCK, serverLevel, enchantmentLevel, itemStack, victim, damageSource, amount);
|
|
}
|
|
|
|
public void modifyKnockback(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity victim, DamageSource damageSource, MutableFloat amount) {
|
|
this.modifyDamageFilteredValue(EnchantmentEffectComponents.KNOCKBACK, serverLevel, enchantmentLevel, itemStack, victim, damageSource, amount);
|
|
}
|
|
|
|
public void modifyArmorEffectivness(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity victim, DamageSource damageSource, MutableFloat amount) {
|
|
this.modifyDamageFilteredValue(EnchantmentEffectComponents.ARMOR_EFFECTIVENESS, serverLevel, enchantmentLevel, itemStack, victim, damageSource, amount);
|
|
}
|
|
|
|
public void doPostAttack(ServerLevel serverLevel, int enchantmentLevel, EnchantedItemInUse item, EnchantmentTarget forTarget, Entity victim, DamageSource damageSource) {
|
|
for (TargetedConditionalEffect effect : this.getEffects(EnchantmentEffectComponents.POST_ATTACK)) {
|
|
if (forTarget != effect.enchanted()) continue;
|
|
Enchantment.doPostAttack(effect, serverLevel, enchantmentLevel, item, victim, damageSource);
|
|
}
|
|
}
|
|
|
|
public static void doPostAttack(TargetedConditionalEffect<EnchantmentEntityEffect> effect, ServerLevel serverLevel, int enchantmentLevel, EnchantedItemInUse item, Entity victim, DamageSource damageSource) {
|
|
if (effect.matches(Enchantment.damageContext(serverLevel, enchantmentLevel, victim, damageSource))) {
|
|
Entity target;
|
|
switch (effect.affected()) {
|
|
default: {
|
|
throw new MatchException(null, null);
|
|
}
|
|
case ATTACKER: {
|
|
Entity entity = damageSource.getEntity();
|
|
break;
|
|
}
|
|
case DAMAGING_ENTITY: {
|
|
Entity entity = damageSource.getDirectEntity();
|
|
break;
|
|
}
|
|
case VICTIM: {
|
|
Entity entity = target = victim;
|
|
}
|
|
}
|
|
if (target != null) {
|
|
effect.effect().apply(serverLevel, enchantmentLevel, item, target, target.position());
|
|
}
|
|
}
|
|
}
|
|
|
|
public void doLunge(ServerLevel serverLevel, int enchantmentLevel, EnchantedItemInUse item, Entity user) {
|
|
Enchantment.applyEffects(this.getEffects(EnchantmentEffectComponents.POST_PIERCING_ATTACK), Enchantment.entityContext(serverLevel, enchantmentLevel, user, user.position()), e -> e.apply(serverLevel, enchantmentLevel, item, user, user.position()));
|
|
}
|
|
|
|
public void modifyProjectileCount(ServerLevel serverLevel, int enchantmentLevel, ItemStack weapon, Entity shooter, MutableFloat count) {
|
|
this.modifyEntityFilteredValue(EnchantmentEffectComponents.PROJECTILE_COUNT, serverLevel, enchantmentLevel, weapon, shooter, count);
|
|
}
|
|
|
|
public void modifyProjectileSpread(ServerLevel serverLevel, int enchantmentLevel, ItemStack weapon, Entity shooter, MutableFloat angle) {
|
|
this.modifyEntityFilteredValue(EnchantmentEffectComponents.PROJECTILE_SPREAD, serverLevel, enchantmentLevel, weapon, shooter, angle);
|
|
}
|
|
|
|
public void modifyCrossbowChargeTime(RandomSource random, int enchantmentLevel, MutableFloat time) {
|
|
this.modifyUnfilteredValue(EnchantmentEffectComponents.CROSSBOW_CHARGE_TIME, random, enchantmentLevel, time);
|
|
}
|
|
|
|
public void modifyUnfilteredValue(DataComponentType<EnchantmentValueEffect> component, RandomSource random, int enchantmentLevel, MutableFloat value) {
|
|
EnchantmentValueEffect effect = this.effects.get(component);
|
|
if (effect != null) {
|
|
value.setValue(effect.process(enchantmentLevel, random, value.floatValue()));
|
|
}
|
|
}
|
|
|
|
public void tick(ServerLevel serverLevel, int enchantmentLevel, EnchantedItemInUse item, Entity entity) {
|
|
Enchantment.applyEffects(this.getEffects(EnchantmentEffectComponents.TICK), Enchantment.entityContext(serverLevel, enchantmentLevel, entity, entity.position()), e -> e.apply(serverLevel, enchantmentLevel, item, entity, entity.position()));
|
|
}
|
|
|
|
public void onProjectileSpawned(ServerLevel serverLevel, int enchantmentLevel, EnchantedItemInUse weapon, Entity projectile) {
|
|
Enchantment.applyEffects(this.getEffects(EnchantmentEffectComponents.PROJECTILE_SPAWNED), Enchantment.entityContext(serverLevel, enchantmentLevel, projectile, projectile.position()), e -> e.apply(serverLevel, enchantmentLevel, weapon, projectile, projectile.position()));
|
|
}
|
|
|
|
public void onHitBlock(ServerLevel serverLevel, int enchantmentLevel, EnchantedItemInUse weapon, Entity projectile, Vec3 position, BlockState hitBlock) {
|
|
Enchantment.applyEffects(this.getEffects(EnchantmentEffectComponents.HIT_BLOCK), Enchantment.blockHitContext(serverLevel, enchantmentLevel, projectile, position, hitBlock), e -> e.apply(serverLevel, enchantmentLevel, weapon, projectile, position));
|
|
}
|
|
|
|
private void modifyItemFilteredCount(DataComponentType<List<ConditionalEffect<EnchantmentValueEffect>>> effectType, ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, MutableFloat value) {
|
|
Enchantment.applyEffects(this.getEffects(effectType), Enchantment.itemContext(serverLevel, enchantmentLevel, itemStack), e -> value.setValue(e.process(enchantmentLevel, serverLevel.getRandom(), value.floatValue())));
|
|
}
|
|
|
|
private void modifyEntityFilteredValue(DataComponentType<List<ConditionalEffect<EnchantmentValueEffect>>> effectType, ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity entity, MutableFloat value) {
|
|
Enchantment.applyEffects(this.getEffects(effectType), Enchantment.entityContext(serverLevel, enchantmentLevel, entity, entity.position()), e -> value.setValue(e.process(enchantmentLevel, entity.getRandom(), value.floatValue())));
|
|
}
|
|
|
|
private void modifyDamageFilteredValue(DataComponentType<List<ConditionalEffect<EnchantmentValueEffect>>> effectType, ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack, Entity victim, DamageSource damageSource, MutableFloat value) {
|
|
Enchantment.applyEffects(this.getEffects(effectType), Enchantment.damageContext(serverLevel, enchantmentLevel, victim, damageSource), e -> value.setValue(e.process(enchantmentLevel, victim.getRandom(), value.floatValue())));
|
|
}
|
|
|
|
public static LootContext damageContext(ServerLevel serverLevel, int enchantmentLevel, Entity victim, DamageSource source) {
|
|
LootParams params = new LootParams.Builder(serverLevel).withParameter(LootContextParams.THIS_ENTITY, victim).withParameter(LootContextParams.ENCHANTMENT_LEVEL, enchantmentLevel).withParameter(LootContextParams.ORIGIN, victim.position()).withParameter(LootContextParams.DAMAGE_SOURCE, source).withOptionalParameter(LootContextParams.ATTACKING_ENTITY, source.getEntity()).withOptionalParameter(LootContextParams.DIRECT_ATTACKING_ENTITY, source.getDirectEntity()).create(LootContextParamSets.ENCHANTED_DAMAGE);
|
|
return new LootContext.Builder(params).create(Optional.empty());
|
|
}
|
|
|
|
private static LootContext itemContext(ServerLevel serverLevel, int enchantmentLevel, ItemStack itemStack) {
|
|
LootParams params = new LootParams.Builder(serverLevel).withParameter(LootContextParams.TOOL, itemStack).withParameter(LootContextParams.ENCHANTMENT_LEVEL, enchantmentLevel).create(LootContextParamSets.ENCHANTED_ITEM);
|
|
return new LootContext.Builder(params).create(Optional.empty());
|
|
}
|
|
|
|
private static LootContext locationContext(ServerLevel serverLevel, int enchantmentLevel, Entity entity, boolean active) {
|
|
LootParams params = new LootParams.Builder(serverLevel).withParameter(LootContextParams.THIS_ENTITY, entity).withParameter(LootContextParams.ENCHANTMENT_LEVEL, enchantmentLevel).withParameter(LootContextParams.ORIGIN, entity.position()).withParameter(LootContextParams.ENCHANTMENT_ACTIVE, active).create(LootContextParamSets.ENCHANTED_LOCATION);
|
|
return new LootContext.Builder(params).create(Optional.empty());
|
|
}
|
|
|
|
private static LootContext entityContext(ServerLevel serverLevel, int enchantmentLevel, Entity entity, Vec3 position) {
|
|
LootParams params = new LootParams.Builder(serverLevel).withParameter(LootContextParams.THIS_ENTITY, entity).withParameter(LootContextParams.ENCHANTMENT_LEVEL, enchantmentLevel).withParameter(LootContextParams.ORIGIN, position).create(LootContextParamSets.ENCHANTED_ENTITY);
|
|
return new LootContext.Builder(params).create(Optional.empty());
|
|
}
|
|
|
|
private static LootContext blockHitContext(ServerLevel serverLevel, int enchantmentLevel, Entity entity, Vec3 position, BlockState hitBlock) {
|
|
LootParams params = new LootParams.Builder(serverLevel).withParameter(LootContextParams.THIS_ENTITY, entity).withParameter(LootContextParams.ENCHANTMENT_LEVEL, enchantmentLevel).withParameter(LootContextParams.ORIGIN, position).withParameter(LootContextParams.BLOCK_STATE, hitBlock).create(LootContextParamSets.HIT_BLOCK);
|
|
return new LootContext.Builder(params).create(Optional.empty());
|
|
}
|
|
|
|
private static <T> void applyEffects(List<ConditionalEffect<T>> effects, LootContext filterData, Consumer<T> action) {
|
|
for (ConditionalEffect<T> conditionalEffect : effects) {
|
|
if (!conditionalEffect.matches(filterData)) continue;
|
|
action.accept(conditionalEffect.effect());
|
|
}
|
|
}
|
|
|
|
public void runLocationChangedEffects(ServerLevel serverLevel, int enchantmentLevel, EnchantedItemInUse item, LivingEntity entity) {
|
|
EquipmentSlot slot = item.inSlot();
|
|
if (slot == null) {
|
|
return;
|
|
}
|
|
Map<Enchantment, Set<EnchantmentLocationBasedEffect>> activeLocationDependentEffects = entity.activeLocationDependentEnchantments(slot);
|
|
if (!this.matchingSlot(slot)) {
|
|
Set<EnchantmentLocationBasedEffect> activeEffects = activeLocationDependentEffects.remove(this);
|
|
if (activeEffects != null) {
|
|
activeEffects.forEach(effect -> effect.onDeactivated(item, entity, entity.position(), enchantmentLevel));
|
|
}
|
|
return;
|
|
}
|
|
ObjectArraySet activeEffects = activeLocationDependentEffects.get(this);
|
|
for (ConditionalEffect filteredEffect : this.getEffects(EnchantmentEffectComponents.LOCATION_CHANGED)) {
|
|
boolean wasActive;
|
|
EnchantmentLocationBasedEffect effect2 = (EnchantmentLocationBasedEffect)filteredEffect.effect();
|
|
boolean bl = wasActive = activeEffects != null && activeEffects.contains(effect2);
|
|
if (filteredEffect.matches(Enchantment.locationContext(serverLevel, enchantmentLevel, entity, wasActive))) {
|
|
if (!wasActive) {
|
|
if (activeEffects == null) {
|
|
activeEffects = new ObjectArraySet();
|
|
activeLocationDependentEffects.put(this, (Set<EnchantmentLocationBasedEffect>)activeEffects);
|
|
}
|
|
activeEffects.add((EnchantmentLocationBasedEffect)effect2);
|
|
}
|
|
effect2.onChangedBlock(serverLevel, enchantmentLevel, item, entity, entity.position(), !wasActive);
|
|
continue;
|
|
}
|
|
if (activeEffects == null || !activeEffects.remove(effect2)) continue;
|
|
effect2.onDeactivated(item, entity, entity.position(), enchantmentLevel);
|
|
}
|
|
if (activeEffects != null && activeEffects.isEmpty()) {
|
|
activeLocationDependentEffects.remove(this);
|
|
}
|
|
}
|
|
|
|
public void stopLocationBasedEffects(int enchantmentLevel, EnchantedItemInUse item, LivingEntity entity) {
|
|
EquipmentSlot slot = item.inSlot();
|
|
if (slot == null) {
|
|
return;
|
|
}
|
|
Set<EnchantmentLocationBasedEffect> activeEffects = entity.activeLocationDependentEnchantments(slot).remove(this);
|
|
if (activeEffects == null) {
|
|
return;
|
|
}
|
|
for (EnchantmentLocationBasedEffect effect : activeEffects) {
|
|
effect.onDeactivated(item, entity, entity.position(), enchantmentLevel);
|
|
}
|
|
}
|
|
|
|
public static Builder enchantment(EnchantmentDefinition definition) {
|
|
return new Builder(definition);
|
|
}
|
|
|
|
public record EnchantmentDefinition(HolderSet<Item> supportedItems, Optional<HolderSet<Item>> primaryItems, int weight, int maxLevel, Cost minCost, Cost maxCost, int anvilCost, List<EquipmentSlotGroup> slots) {
|
|
public static final MapCodec<EnchantmentDefinition> CODEC = RecordCodecBuilder.mapCodec(i -> i.group((App)RegistryCodecs.homogeneousList(Registries.ITEM).fieldOf("supported_items").forGetter(EnchantmentDefinition::supportedItems), (App)RegistryCodecs.homogeneousList(Registries.ITEM).optionalFieldOf("primary_items").forGetter(EnchantmentDefinition::primaryItems), (App)ExtraCodecs.intRange(1, 1024).fieldOf("weight").forGetter(EnchantmentDefinition::weight), (App)ExtraCodecs.intRange(1, 255).fieldOf("max_level").forGetter(EnchantmentDefinition::maxLevel), (App)Cost.CODEC.fieldOf("min_cost").forGetter(EnchantmentDefinition::minCost), (App)Cost.CODEC.fieldOf("max_cost").forGetter(EnchantmentDefinition::maxCost), (App)ExtraCodecs.NON_NEGATIVE_INT.fieldOf("anvil_cost").forGetter(EnchantmentDefinition::anvilCost), (App)EquipmentSlotGroup.CODEC.listOf().fieldOf("slots").forGetter(EnchantmentDefinition::slots)).apply((Applicative)i, EnchantmentDefinition::new));
|
|
}
|
|
|
|
public record Cost(int base, int perLevelAboveFirst) {
|
|
public static final Codec<Cost> CODEC = RecordCodecBuilder.create(i -> i.group((App)Codec.INT.fieldOf("base").forGetter(Cost::base), (App)Codec.INT.fieldOf("per_level_above_first").forGetter(Cost::perLevelAboveFirst)).apply((Applicative)i, Cost::new));
|
|
|
|
public int calculate(int level) {
|
|
return this.base + this.perLevelAboveFirst * (level - 1);
|
|
}
|
|
}
|
|
|
|
public static class Builder {
|
|
private final EnchantmentDefinition definition;
|
|
private HolderSet<Enchantment> exclusiveSet = HolderSet.direct(new Holder[0]);
|
|
private final Map<DataComponentType<?>, List<?>> effectLists = new HashMap();
|
|
private final DataComponentMap.Builder effectMapBuilder = DataComponentMap.builder();
|
|
|
|
public Builder(EnchantmentDefinition definition) {
|
|
this.definition = definition;
|
|
}
|
|
|
|
public Builder exclusiveWith(HolderSet<Enchantment> set) {
|
|
this.exclusiveSet = set;
|
|
return this;
|
|
}
|
|
|
|
public <E> Builder withEffect(DataComponentType<List<ConditionalEffect<E>>> type, E effect, LootItemCondition.Builder condition) {
|
|
this.getEffectsList(type).add(new ConditionalEffect<E>(effect, Optional.of(condition.build())));
|
|
return this;
|
|
}
|
|
|
|
public <E> Builder withEffect(DataComponentType<List<ConditionalEffect<E>>> type, E effect) {
|
|
this.getEffectsList(type).add(new ConditionalEffect<E>(effect, Optional.empty()));
|
|
return this;
|
|
}
|
|
|
|
public <E> Builder withEffect(DataComponentType<List<TargetedConditionalEffect<E>>> type, EnchantmentTarget enchanted, EnchantmentTarget affected, E effect, LootItemCondition.Builder condition) {
|
|
this.getEffectsList(type).add(new TargetedConditionalEffect<E>(enchanted, affected, effect, Optional.of(condition.build())));
|
|
return this;
|
|
}
|
|
|
|
public <E> Builder withEffect(DataComponentType<List<TargetedConditionalEffect<E>>> type, EnchantmentTarget enchanted, EnchantmentTarget affected, E effect) {
|
|
this.getEffectsList(type).add(new TargetedConditionalEffect<E>(enchanted, affected, effect, Optional.empty()));
|
|
return this;
|
|
}
|
|
|
|
public Builder withEffect(DataComponentType<List<EnchantmentAttributeEffect>> type, EnchantmentAttributeEffect effect) {
|
|
this.getEffectsList(type).add(effect);
|
|
return this;
|
|
}
|
|
|
|
public <E> Builder withSpecialEffect(DataComponentType<E> type, E effect) {
|
|
this.effectMapBuilder.set(type, effect);
|
|
return this;
|
|
}
|
|
|
|
public Builder withEffect(DataComponentType<Unit> type) {
|
|
this.effectMapBuilder.set(type, Unit.INSTANCE);
|
|
return this;
|
|
}
|
|
|
|
private <E> List<E> getEffectsList(DataComponentType<List<E>> type) {
|
|
return this.effectLists.computeIfAbsent(type, k -> {
|
|
ArrayList newList = new ArrayList();
|
|
this.effectMapBuilder.set(type, newList);
|
|
return newList;
|
|
});
|
|
}
|
|
|
|
public Enchantment build(Identifier descriptionKey) {
|
|
return new Enchantment(Component.translatable(Util.makeDescriptionId("enchantment", descriptionKey)), this.definition, this.exclusiveSet, this.effectMapBuilder.build());
|
|
}
|
|
}
|
|
}
|
|
|