From c7aeb7421fab84dff886408053af70f6d19228e2 Mon Sep 17 00:00:00 2001 From: WakelessSloth56 Date: Fri, 23 Feb 2024 23:08:58 +0800 Subject: [PATCH] feat(adv): loot_enchantment_applied trigger --- .../advancement/HLCriteriaTriggers.java | 2 + .../LootEnchantmentAppliedTrigger.java | 144 ++++++++++++++++++ .../MixinEnchantWithLevelsFunction.java | 59 +++++++ src/main/resources/harmoniclib.mixin.json | 1 + 4 files changed, 206 insertions(+) create mode 100644 src/main/java/org/auioc/mcmod/harmoniclib/advancement/criterion/LootEnchantmentAppliedTrigger.java create mode 100644 src/main/java/org/auioc/mcmod/harmoniclib/mixin/server/MixinEnchantWithLevelsFunction.java diff --git a/src/main/java/org/auioc/mcmod/harmoniclib/advancement/HLCriteriaTriggers.java b/src/main/java/org/auioc/mcmod/harmoniclib/advancement/HLCriteriaTriggers.java index 3b60558..dd02b5e 100644 --- a/src/main/java/org/auioc/mcmod/harmoniclib/advancement/HLCriteriaTriggers.java +++ b/src/main/java/org/auioc/mcmod/harmoniclib/advancement/HLCriteriaTriggers.java @@ -25,6 +25,7 @@ import net.neoforged.neoforge.registries.DeferredRegister; import org.auioc.mcmod.harmoniclib.HarmonicLib; import org.auioc.mcmod.harmoniclib.advancement.criterion.EnchantmentPerformedTrigger; +import org.auioc.mcmod.harmoniclib.advancement.criterion.LootEnchantmentAppliedTrigger; import java.util.function.Supplier; @@ -39,5 +40,6 @@ private static > DeferredHolder, EnchantmentPerformedTrigger> ENCHANTMENT_PERFORMED = register("enchantment_performed", EnchantmentPerformedTrigger::new); + public static final DeferredHolder, LootEnchantmentAppliedTrigger> LOOT_ENCHANTMENT_APPLIED = register("loot_enchantment_applied", LootEnchantmentAppliedTrigger::new); } diff --git a/src/main/java/org/auioc/mcmod/harmoniclib/advancement/criterion/LootEnchantmentAppliedTrigger.java b/src/main/java/org/auioc/mcmod/harmoniclib/advancement/criterion/LootEnchantmentAppliedTrigger.java new file mode 100644 index 0000000..dd348c4 --- /dev/null +++ b/src/main/java/org/auioc/mcmod/harmoniclib/advancement/criterion/LootEnchantmentAppliedTrigger.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2024 AUIOC.ORG + * + * This file is part of HarmonicEnchantments, a mod made for Minecraft. + * + * ArnicaLib is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +package org.auioc.mcmod.harmoniclib.advancement.criterion; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.advancements.Criterion; +import net.minecraft.advancements.critereon.ContextAwarePredicate; +import net.minecraft.advancements.critereon.EntityPredicate; +import net.minecraft.advancements.critereon.ItemPredicate; +import net.minecraft.advancements.critereon.MinMaxBounds; +import net.minecraft.advancements.critereon.SimpleCriterionTrigger; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.util.ExtraCodecs; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.parameters.LootContextParams; +import org.auioc.mcmod.arnicalib.game.codec.EnumCodec; +import org.auioc.mcmod.arnicalib.game.enchantment.HEnchantmentPredicate; +import org.auioc.mcmod.harmoniclib.advancement.HLCriteriaTriggers; +import org.auioc.mcmod.harmoniclib.enchantment.EnchantmentHelper; + +import java.util.Optional; + +public class LootEnchantmentAppliedTrigger extends SimpleCriterionTrigger { + + @Override + public Codec codec() { + return TriggerInstance.CODEC; + } + + public void trigger(ServerPlayer player, ItemStack itemStack) { + this.trigger(player, (instance) -> instance.matches(itemStack)); + } + + public void triggerLootContext(ItemStack itemStack, LootContext lootCtx) { + var entity = lootCtx.getParamOrNull(LootContextParams.KILLER_ENTITY); + if (entity instanceof ServerPlayer player) { + trigger(player, itemStack); + } + } + + public static Criterion createCriterion( + Optional player, Optional item, MinMaxBounds.Ints count, Optional enchantment, Optional requirement + ) { + return HLCriteriaTriggers.LOOT_ENCHANTMENT_APPLIED.get().createCriterion( + new TriggerInstance(player, item, count, enchantment, requirement) + ); + } + + // ============================================================================================================== // + + public record TriggerInstance( + Optional player, + Optional item, + MinMaxBounds.Ints count, + Optional enchantment, + Optional requirement + + ) implements SimpleCriterionTrigger.SimpleInstance { + + public boolean matches(ItemStack itemStack) { + if (item.isPresent() && !item.get().matches(itemStack)) { + return false; + } + + var enchMap = EnchantmentHelper.getEnchantments(itemStack); + + if (count != MinMaxBounds.Ints.ANY && (enchMap.isEmpty() || !count.matches(enchMap.size()))) { + return false; + } + + if (enchantment.isPresent()) { + if (enchMap.isEmpty()) { + return false; + } + + var enchP = enchantment.get(); + int i = (int) enchMap.entrySet().stream().filter(enchP::test).count(); + + var req = requirement.orElse(Requirement.ANY); + if (!req.matches(enchMap.size(), i)) { + return false; + } + } + + return true; + } + + // ========================================================================================================== // + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + ExtraCodecs.strictOptionalField(EntityPredicate.ADVANCEMENT_CODEC, "player").forGetter(TriggerInstance::player), + ExtraCodecs.strictOptionalField(ItemPredicate.CODEC, "item").forGetter(TriggerInstance::item), + ExtraCodecs.strictOptionalField(MinMaxBounds.Ints.CODEC, "count", MinMaxBounds.Ints.ANY).forGetter(TriggerInstance::count), + ExtraCodecs.strictOptionalField(HEnchantmentPredicate.CODEC, "enchantment").forGetter(TriggerInstance::enchantment), + ExtraCodecs.strictOptionalField(EnumCodec.byNameLowerCase(Requirement.class), "enchantment_requirement").forGetter(TriggerInstance::requirement) + ).apply(instance, LootEnchantmentAppliedTrigger.TriggerInstance::new)); + + } + + // ============================================================================================================== // + + public enum Requirement { + ANY { + @Override + public boolean matches(int size, int i) { + return i > 0; + } + }, + ALL { + @Override + public boolean matches(int size, int i) { + return size == i; + } + }, + NONE { + @Override + public boolean matches(int size, int i) { + return i == 0; + } + }; + + public boolean matches(int size, int i) { return false; } + } + +} diff --git a/src/main/java/org/auioc/mcmod/harmoniclib/mixin/server/MixinEnchantWithLevelsFunction.java b/src/main/java/org/auioc/mcmod/harmoniclib/mixin/server/MixinEnchantWithLevelsFunction.java new file mode 100644 index 0000000..49e5385 --- /dev/null +++ b/src/main/java/org/auioc/mcmod/harmoniclib/mixin/server/MixinEnchantWithLevelsFunction.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2024 AUIOC.ORG + * + * This file is part of HarmonicEnchantments, a mod made for Minecraft. + * + * ArnicaLib is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +package org.auioc.mcmod.harmoniclib.mixin.server; + +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.enchantment.EnchantmentHelper; +import net.minecraft.world.level.storage.loot.LootContext; +import net.minecraft.world.level.storage.loot.functions.EnchantWithLevelsFunction; +import net.minecraft.world.level.storage.loot.providers.number.NumberProvider; +import org.auioc.mcmod.harmoniclib.advancement.HLCriteriaTriggers; +import org.auioc.mcmod.harmoniclib.advancement.criterion.LootEnchantmentAppliedTrigger; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.Shadow; + +@Mixin(value = EnchantWithLevelsFunction.class) +public class MixinEnchantWithLevelsFunction { + + @Final + @Shadow + private NumberProvider levels; + + @Final + @Shadow + private boolean treasure; + + /** + * @author WakelessSloth56 + * @reason LootEnchantmentAppliedTrigger {@link LootEnchantmentAppliedTrigger#triggerLootContext} + */ + @Overwrite + public ItemStack run(ItemStack pStack, LootContext pContext) { + RandomSource randomsource = pContext.getRandom(); + var newItemStack = EnchantmentHelper.enchantItem(randomsource, pStack, this.levels.getInt(pContext), this.treasure); + HLCriteriaTriggers.LOOT_ENCHANTMENT_APPLIED.get().triggerLootContext(newItemStack, pContext); + return newItemStack; + } + + +} diff --git a/src/main/resources/harmoniclib.mixin.json b/src/main/resources/harmoniclib.mixin.json index ce8e81e..da753bd 100644 --- a/src/main/resources/harmoniclib.mixin.json +++ b/src/main/resources/harmoniclib.mixin.json @@ -9,6 +9,7 @@ "common.MixinProjectile", "common.MixinSpectralArrow", "server.MixinCatRelaxOnOwnerGoal", + "server.MixinEnchantWithLevelsFunction", "server.MixinPiglinAi" ], "client": [],