diff --git a/gradle.properties b/gradle.properties index 2b5ccf1..59c89bc 100644 --- a/gradle.properties +++ b/gradle.properties @@ -3,17 +3,17 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://fabricmc.net/versions.html - minecraft_version=1.20.5-rc3 - yarn_mappings=1.20.5-rc3+build.1 + minecraft_version=1.20.5 + yarn_mappings=1.20.5+build.1 loader_version=0.15.10 # Mod Properties - mod_version = 3.1.3 + mod_version = 3.2.0 maven_group = de.mschae23.minecraft.mod archives_base_name = grind-enchantments # Dependencies - fabric_api_version=0.97.5+1.20.5 + fabric_api_version=0.97.6+1.20.5 codec_config_api_version=2.0.0+1.20.5-rc3 tax_free_levels_version=loom-SNAPSHOT diff --git a/src/main/java/de/mschae23/grindenchantments/GrindEnchantments.java b/src/main/java/de/mschae23/grindenchantments/GrindEnchantments.java index fe2a4b5..6128cf5 100644 --- a/src/main/java/de/mschae23/grindenchantments/GrindEnchantments.java +++ b/src/main/java/de/mschae23/grindenchantments/GrindEnchantments.java @@ -23,41 +23,27 @@ import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.ItemEnchantmentsComponent; import net.minecraft.component.type.LoreComponent; -import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.item.ItemStack; import net.minecraft.registry.RegistryWrapper; -import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.text.MutableText; import net.minecraft.text.Text; import net.minecraft.util.Formatting; import de.mschae23.grindenchantments.config.DedicatedServerConfig; +import de.mschae23.grindenchantments.config.FilterConfig; import de.mschae23.grindenchantments.cost.CostFunction; import de.mschae23.grindenchantments.item.GrindEnchantmentsDataComponent; -import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; public class GrindEnchantments { - public static int getLevelCost(ItemStack stack, CostFunction costFunction, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup) { + public static int getLevelCost(ItemStack stack, CostFunction costFunction, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup) { ItemEnchantmentsComponent enchantments = EnchantmentHelper.getEnchantments(stack); - double cost = costFunction.getCost(enchantments, allowCurses, wrapperLookup); + double cost = costFunction.getCost(enchantments, filter, wrapperLookup); return (int) Math.ceil(cost); } - public static Object2IntMap> getEnchantments(ItemStack stack, boolean allowCurses) { - Object2IntMap> enchantments = new Object2IntOpenHashMap<>(EnchantmentHelper.getEnchantments(stack).enchantments); - - if (!allowCurses) { - // Don't transfer curses if it isn't enabled in the config - for (RegistryEntry entry : enchantments.keySet()) { - if (entry.value().isCursed()) { - enchantments.removeInt(entry); - } - } - } - - return enchantments; + public static ItemEnchantmentsComponent getEnchantments(ItemStack stack, FilterConfig filter) { + return filter.filter(EnchantmentHelper.getEnchantments(stack)); } public static ItemStack addLevelCostComponent(ItemStack stack, IntSupplier cost, boolean canTakeItem, DedicatedServerConfig config) { diff --git a/src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java b/src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java index 608df8e..be70e5f 100644 --- a/src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java +++ b/src/main/java/de/mschae23/grindenchantments/GrindEnchantmentsMod.java @@ -30,13 +30,15 @@ import de.mschae23.config.api.ModConfig; import com.mojang.serialization.Codec; import com.mojang.serialization.JsonOps; -import de.mschae23.grindenchantments.config.GrindEnchantmentsV2Config; +import de.mschae23.grindenchantments.config.GrindEnchantmentsV3Config; import de.mschae23.grindenchantments.config.v1.GrindEnchantmentsV1Config; +import de.mschae23.grindenchantments.config.v2.GrindEnchantmentsV2Config; import de.mschae23.grindenchantments.cost.CostFunctionType; import de.mschae23.grindenchantments.event.ApplyLevelCostEvent; import de.mschae23.grindenchantments.event.GrindstoneEvents; import de.mschae23.grindenchantments.impl.DisenchantOperation; import de.mschae23.grindenchantments.impl.MoveOperation; +import de.mschae23.grindenchantments.impl.ResetRepairCostOperation; import de.mschae23.grindenchantments.item.GrindEnchantmentsDataComponent; import de.mschae23.grindenchantments.registry.GrindEnchantmentsRegistries; import io.github.fourmisain.taxfreelevels.TaxFreeLevels; @@ -50,11 +52,11 @@ public class GrindEnchantmentsMod implements ModInitializer { public static final Path CONFIG_PATH = Paths.get(MODID + ".json"); - private static final GrindEnchantmentsV2Config LATEST_CONFIG_DEFAULT = GrindEnchantmentsV2Config.DEFAULT; + private static final GrindEnchantmentsV3Config LATEST_CONFIG_DEFAULT = GrindEnchantmentsV3Config.DEFAULT; private static final int LATEST_CONFIG_VERSION = LATEST_CONFIG_DEFAULT.version(); - private static final Codec> CONFIG_CODEC = ModConfig.createCodec(LATEST_CONFIG_VERSION, GrindEnchantmentsMod::getConfigType); + private static final Codec> CONFIG_CODEC = ModConfig.createCodec(LATEST_CONFIG_VERSION, GrindEnchantmentsMod::getConfigType); - private static GrindEnchantmentsV2Config CONFIG = LATEST_CONFIG_DEFAULT; + private static GrindEnchantmentsV3Config CONFIG = LATEST_CONFIG_DEFAULT; @Override public void onInitialize() { @@ -70,9 +72,11 @@ public void onInitialize() { DisenchantOperation disenchant = new DisenchantOperation(); MoveOperation move = new MoveOperation(); + ResetRepairCostOperation resetRepairCost = new ResetRepairCostOperation(); GrindstoneEvents.registerAll(disenchant); GrindstoneEvents.registerAll(move); + GrindstoneEvents.registerAll(resetRepairCost); ApplyLevelCostEvent.EVENT.register(ApplyLevelCostEvent.DEFAULT, (cost, player) -> { player.addExperienceLevels(-cost); @@ -89,15 +93,15 @@ public void onInitialize() { } @SuppressWarnings("deprecation") - private static ModConfig.Type getConfigType(int version) { - //noinspection SwitchStatementWithTooFewBranches + private static ModConfig.Type getConfigType(int version) { return new ModConfig.Type<>(version, switch (version) { case 1 -> GrindEnchantmentsV1Config.TYPE_CODEC; - default -> GrindEnchantmentsV2Config.TYPE_CODEC; + case 2 -> GrindEnchantmentsV2Config.TYPE_CODEC; + default -> GrindEnchantmentsV3Config.TYPE_CODEC; }); } - public static GrindEnchantmentsV2Config getConfig() { + public static GrindEnchantmentsV3Config getConfig() { return CONFIG; } diff --git a/src/main/java/de/mschae23/grindenchantments/config/DisenchantConfig.java b/src/main/java/de/mschae23/grindenchantments/config/DisenchantConfig.java index ef5c86d..893ade9 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/DisenchantConfig.java +++ b/src/main/java/de/mschae23/grindenchantments/config/DisenchantConfig.java @@ -21,6 +21,7 @@ import de.mschae23.grindenchantments.cost.CostFunction; import de.mschae23.grindenchantments.cost.CountMinPowerCostFunction; +import de.mschae23.grindenchantments.cost.FilterCostFunction; import de.mschae23.grindenchantments.cost.TransformCostFunction; import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; @@ -33,5 +34,5 @@ public record DisenchantConfig(boolean enabled, boolean consumeItem, CostFunctio ).apply(instance, instance.stable(DisenchantConfig::new))); public static final DisenchantConfig DEFAULT = new DisenchantConfig(true, false, - new TransformCostFunction(new CountMinPowerCostFunction(), 0.3, 8.0)); + new FilterCostFunction(new TransformCostFunction(new CountMinPowerCostFunction(), 0.3, 8.0))); } diff --git a/src/main/java/de/mschae23/grindenchantments/config/FilterAction.java b/src/main/java/de/mschae23/grindenchantments/config/FilterAction.java new file mode 100644 index 0000000..61386cf --- /dev/null +++ b/src/main/java/de/mschae23/grindenchantments/config/FilterAction.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2024 mschae23 + * + * This file is part of Grind enchantments. + * + * Grind enchantments is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package de.mschae23.grindenchantments.config; + +import net.minecraft.util.StringIdentifiable; +import com.mojang.serialization.Codec; + +public enum FilterAction implements StringIdentifiable { + ALLOW("allow"), + IGNORE("ignore"), + DENY("deny"); + + public static final Codec CODEC = StringIdentifiable.createCodec(FilterAction::values); + public static final Codec NON_IGNORE_CODEC = StringIdentifiable.createCodec(() -> new FilterAction[] { ALLOW, DENY, }); + + private final String name; + + FilterAction(String name) { + this.name = name; + } + + @Override + public String asString() { + return this.name; + } +} diff --git a/src/main/java/de/mschae23/grindenchantments/config/FilterConfig.java b/src/main/java/de/mschae23/grindenchantments/config/FilterConfig.java new file mode 100644 index 0000000..5222b17 --- /dev/null +++ b/src/main/java/de/mschae23/grindenchantments/config/FilterConfig.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2024 mschae23 + * + * This file is part of Grind enchantments. + * + * Grind enchantments is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package de.mschae23.grindenchantments.config; + +import net.minecraft.component.type.ItemEnchantmentsComponent; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.item.Item; +import net.minecraft.registry.RegistryCodecs; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.registry.entry.RegistryEntryList; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +public record FilterConfig(boolean enabled, ItemConfig item, EnchantmentConfig enchantment, FilterAction curses) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.BOOL.fieldOf("enabled").forGetter(FilterConfig::enabled), + ItemConfig.CODEC.fieldOf("item").forGetter(FilterConfig::item), + EnchantmentConfig.CODEC.fieldOf("enchantment").forGetter(FilterConfig::enchantment), + FilterAction.CODEC.fieldOf("cursed_enchantments").forGetter(FilterConfig::curses) + ).apply(instance, instance.stable(FilterConfig::new))); + + public static final FilterConfig DEFAULT = new FilterConfig(true, ItemConfig.DEFAULT, EnchantmentConfig.DEFAULT, FilterAction.IGNORE); + + public ItemEnchantmentsComponent filter(ItemEnchantmentsComponent enchantments) { + if (!this.enabled) { + return enchantments; + } + + ItemEnchantmentsComponent.Builder builder = new ItemEnchantmentsComponent.Builder(enchantments); + + if (this.curses == FilterAction.DENY) { + for (RegistryEntry entry : builder.getEnchantments()) { + if (entry.value().isCursed()) { + return ItemEnchantmentsComponent.DEFAULT; + } + } + } + + if (this.enchantment.action == FilterAction.DENY) { + for (RegistryEntry entry : builder.getEnchantments()) { + if (this.enchantment.enchantments.contains(entry)) { + return ItemEnchantmentsComponent.DEFAULT; + } + } + } + + builder.remove(enchantment -> + ((this.curses == FilterAction.IGNORE) && enchantment.value().isCursed()) + || ((this.enchantment.action == FilterAction.IGNORE) == this.enchantment.enchantments.contains(enchantment))); + + return builder.build(); + } + + public ItemEnchantmentsComponent filterReversed(ItemEnchantmentsComponent enchantments) { + if (!this.enabled) { + return ItemEnchantmentsComponent.DEFAULT; + } + + ItemEnchantmentsComponent.Builder builder = new ItemEnchantmentsComponent.Builder(enchantments); + + if (this.curses == FilterAction.DENY) { + for (RegistryEntry entry : builder.getEnchantments()) { + if (entry.value().isCursed()) { + return ItemEnchantmentsComponent.DEFAULT; + } + } + } + + if (this.enchantment.action == FilterAction.DENY) { + for (RegistryEntry entry : builder.getEnchantments()) { + if (this.enchantment.enchantments.contains(entry)) { + return ItemEnchantmentsComponent.DEFAULT; + } + } + } + + builder.remove(enchantment -> + ((this.curses == FilterAction.ALLOW) || !enchantment.value().isCursed()) + && ((this.enchantment.action == FilterAction.ALLOW) == this.enchantment.enchantments.contains(enchantment))); + + return builder.build(); + } + + public record ItemConfig(RegistryEntryList items, FilterAction action) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + RegistryCodecs.entryList(RegistryKeys.ITEM).fieldOf("enchantments").forGetter(ItemConfig::items), + FilterAction.NON_IGNORE_CODEC.fieldOf("action").forGetter(ItemConfig::action) + ).apply(instance, instance.stable(ItemConfig::new))); + + public static final ItemConfig DEFAULT = new ItemConfig(RegistryEntryList.empty(), FilterAction.DENY); + } + + public record EnchantmentConfig(RegistryEntryList enchantments, FilterAction action) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + RegistryCodecs.entryList(RegistryKeys.ENCHANTMENT).fieldOf("enchantments").forGetter(EnchantmentConfig::enchantments), + FilterAction.CODEC.fieldOf("action").forGetter(EnchantmentConfig::action) + ).apply(instance, instance.stable(EnchantmentConfig::new))); + + public static final EnchantmentConfig DEFAULT = new EnchantmentConfig(RegistryEntryList.empty(), FilterAction.IGNORE); + } +} diff --git a/src/main/java/de/mschae23/grindenchantments/config/GrindEnchantmentsV3Config.java b/src/main/java/de/mschae23/grindenchantments/config/GrindEnchantmentsV3Config.java new file mode 100644 index 0000000..7ae0740 --- /dev/null +++ b/src/main/java/de/mschae23/grindenchantments/config/GrindEnchantmentsV3Config.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2024 mschae23 + * + * This file is part of Grind enchantments. + * + * Grind enchantments is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package de.mschae23.grindenchantments.config; + +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.config.api.ModConfig; + +public record GrindEnchantmentsV3Config(DisenchantConfig disenchant, MoveConfig move, ResetRepairCostConfig resetRepairCost, + FilterConfig filter, + DedicatedServerConfig dedicatedServerConfig, ClientConfig clientConfig) implements ModConfig { + public static final MapCodec TYPE_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + DisenchantConfig.CODEC.fieldOf("disenchant_to_book").forGetter(GrindEnchantmentsV3Config::disenchant), + MoveConfig.CODEC.fieldOf("move_enchantments").forGetter(GrindEnchantmentsV3Config::move), + ResetRepairCostConfig.CODEC.fieldOf("reset_repair_cost").forGetter(GrindEnchantmentsV3Config::resetRepairCost), + FilterConfig.CODEC.fieldOf("filter").forGetter(GrindEnchantmentsV3Config::filter), + DedicatedServerConfig.CODEC.orElse(DedicatedServerConfig.DEFAULT).fieldOf("dedicated_server_options").forGetter(GrindEnchantmentsV3Config::dedicatedServerConfig), + ClientConfig.CODEC.fieldOf("client_options").forGetter(GrindEnchantmentsV3Config::clientConfig) + ).apply(instance, instance.stable(GrindEnchantmentsV3Config::new))); + + public static final ModConfig.Type TYPE = new ModConfig.Type<>(3, TYPE_CODEC); + + public static final GrindEnchantmentsV3Config DEFAULT = + new GrindEnchantmentsV3Config(DisenchantConfig.DEFAULT, MoveConfig.DEFAULT, ResetRepairCostConfig.DEFAULT, FilterConfig.DEFAULT, DedicatedServerConfig.DEFAULT, ClientConfig.DEFAULT); + + @Override + public Type type() { + return TYPE; + } + + @Override + public GrindEnchantmentsV3Config latest() { + return this; + } + + @Override + public boolean shouldUpdate() { + return true; + } +} diff --git a/src/main/java/de/mschae23/grindenchantments/config/MoveConfig.java b/src/main/java/de/mschae23/grindenchantments/config/MoveConfig.java index 67f6d5b..e534497 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/MoveConfig.java +++ b/src/main/java/de/mschae23/grindenchantments/config/MoveConfig.java @@ -21,6 +21,7 @@ import de.mschae23.grindenchantments.cost.CostFunction; import de.mschae23.grindenchantments.cost.CountLevelsCostFunction; +import de.mschae23.grindenchantments.cost.FilterCostFunction; import de.mschae23.grindenchantments.cost.TransformCostFunction; import de.mschae23.grindenchantments.cost.FirstEnchantmentCostFunction; import com.mojang.serialization.Codec; @@ -33,5 +34,6 @@ public record MoveConfig(boolean enabled, CostFunction costFunction) { ).apply(instance, instance.stable(MoveConfig::new))); public static final MoveConfig DEFAULT = new MoveConfig(true, - new TransformCostFunction(new FirstEnchantmentCostFunction(new CountLevelsCostFunction(3.0, 8.0)), 0.5, 0.5)); + new FilterCostFunction(new FirstEnchantmentCostFunction(new TransformCostFunction( + new CountLevelsCostFunction(3.0, 8.0), 0.5, 0.5)))); } diff --git a/src/main/java/de/mschae23/grindenchantments/config/ResetRepairCostConfig.java b/src/main/java/de/mschae23/grindenchantments/config/ResetRepairCostConfig.java new file mode 100644 index 0000000..48bc922 --- /dev/null +++ b/src/main/java/de/mschae23/grindenchantments/config/ResetRepairCostConfig.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2024 mschae23 + * + * This file is part of Grind enchantments. + * + * Grind enchantments is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package de.mschae23.grindenchantments.config; + +import net.minecraft.item.Item; +import net.minecraft.item.Items; +import net.minecraft.registry.RegistryCodecs; +import net.minecraft.registry.RegistryKeys; +import net.minecraft.registry.entry.RegistryEntryList; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.cost.AverageCountCostFunction; +import de.mschae23.grindenchantments.cost.CostFunction; +import de.mschae23.grindenchantments.cost.CountLevelsCostFunction; +import de.mschae23.grindenchantments.cost.TransformCostFunction; + +public record ResetRepairCostConfig(boolean enabled, RegistryEntryList catalystItems, boolean requiresEnchantment, CostFunction costFunction) { + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + Codec.BOOL.fieldOf("enabled").forGetter(ResetRepairCostConfig::enabled), + RegistryCodecs.entryList(RegistryKeys.ITEM).fieldOf("catalyst_items").forGetter(ResetRepairCostConfig::catalystItems), + Codec.BOOL.fieldOf("requires_enchantment").forGetter(ResetRepairCostConfig::requiresEnchantment), + CostFunction.TYPE_CODEC.fieldOf("cost_function").forGetter(ResetRepairCostConfig::costFunction) + ).apply(instance, instance.stable(ResetRepairCostConfig::new))); + + @SuppressWarnings("deprecation") + public static final ResetRepairCostConfig DEFAULT = new ResetRepairCostConfig(false, + RegistryEntryList.of(Items.DIAMOND.getRegistryEntry()), true, + // Intentionally no filter function + new TransformCostFunction(new AverageCountCostFunction(new CountLevelsCostFunction(1.0, 4.0)), 1.5, 4.0)); +} diff --git a/src/main/java/de/mschae23/grindenchantments/config/v1/GrindEnchantmentsV1Config.java b/src/main/java/de/mschae23/grindenchantments/config/v1/GrindEnchantmentsV1Config.java index 485a5fe..933c292 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/v1/GrindEnchantmentsV1Config.java +++ b/src/main/java/de/mschae23/grindenchantments/config/v1/GrindEnchantmentsV1Config.java @@ -23,16 +23,17 @@ import de.mschae23.grindenchantments.config.ClientConfig; import de.mschae23.grindenchantments.config.DedicatedServerConfig; import de.mschae23.grindenchantments.config.DisenchantConfig; -import de.mschae23.grindenchantments.config.GrindEnchantmentsV2Config; +import de.mschae23.grindenchantments.config.GrindEnchantmentsV3Config; import de.mschae23.grindenchantments.config.MoveConfig; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.config.v2.GrindEnchantmentsV2Config; @Deprecated @SuppressWarnings("DeprecatedIsStillUsed") public record GrindEnchantmentsV1Config(DisenchantConfig disenchant, MoveConfig move, boolean allowCurses, - DedicatedServerConfig dedicatedServerConfig, ClientConfig clientConfig) implements ModConfig { + DedicatedServerConfig dedicatedServerConfig, ClientConfig clientConfig) implements ModConfig { public static final MapCodec TYPE_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( DisenchantConfig.CODEC.fieldOf("disenchant_to_book").forGetter(GrindEnchantmentsV1Config::disenchant), MoveConfig.CODEC.fieldOf("move_enchantments").forGetter(GrindEnchantmentsV1Config::move), @@ -41,19 +42,19 @@ public record GrindEnchantmentsV1Config(DisenchantConfig disenchant, MoveConfig ClientConfig.CODEC.fieldOf("client_options").forGetter(GrindEnchantmentsV1Config::clientConfig) ).apply(instance, instance.stable(GrindEnchantmentsV1Config::new))); - public static final Type TYPE = new Type<>(1, TYPE_CODEC); + public static final Type TYPE = new Type<>(1, TYPE_CODEC); public static final GrindEnchantmentsV1Config DEFAULT = new GrindEnchantmentsV1Config(DisenchantConfig.DEFAULT, MoveConfig.DEFAULT, false, DedicatedServerConfig.DEFAULT, ClientConfig.DEFAULT); @Override - public Type type() { + public Type type() { return TYPE; } @Override - public GrindEnchantmentsV2Config latest() { - return new GrindEnchantmentsV2Config(this.disenchant, this.move, this.allowCurses, this.dedicatedServerConfig, this.clientConfig); + public GrindEnchantmentsV3Config latest() { + return new GrindEnchantmentsV2Config(this.disenchant, this.move, this.allowCurses, this.dedicatedServerConfig, this.clientConfig).latest(); } @Override diff --git a/src/main/java/de/mschae23/grindenchantments/config/GrindEnchantmentsV2Config.java b/src/main/java/de/mschae23/grindenchantments/config/v2/GrindEnchantmentsV2Config.java similarity index 58% rename from src/main/java/de/mschae23/grindenchantments/config/GrindEnchantmentsV2Config.java rename to src/main/java/de/mschae23/grindenchantments/config/v2/GrindEnchantmentsV2Config.java index 2bbdd94..e0a1790 100644 --- a/src/main/java/de/mschae23/grindenchantments/config/GrindEnchantmentsV2Config.java +++ b/src/main/java/de/mschae23/grindenchantments/config/v2/GrindEnchantmentsV2Config.java @@ -17,15 +17,26 @@ * along with this program. If not, see . */ -package de.mschae23.grindenchantments.config; +package de.mschae23.grindenchantments.config.v2; -import de.mschae23.config.api.ModConfig; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.config.api.ModConfig; +import de.mschae23.grindenchantments.config.ClientConfig; +import de.mschae23.grindenchantments.config.DedicatedServerConfig; +import de.mschae23.grindenchantments.config.DisenchantConfig; +import de.mschae23.grindenchantments.config.FilterAction; +import de.mschae23.grindenchantments.config.FilterConfig; +import de.mschae23.grindenchantments.config.GrindEnchantmentsV3Config; +import de.mschae23.grindenchantments.config.MoveConfig; +import de.mschae23.grindenchantments.config.ResetRepairCostConfig; +import de.mschae23.grindenchantments.cost.FilterCostFunction; +@Deprecated +@SuppressWarnings("DeprecatedIsStillUsed") public record GrindEnchantmentsV2Config(DisenchantConfig disenchant, MoveConfig move, boolean allowCurses, - DedicatedServerConfig dedicatedServerConfig, ClientConfig clientConfig) implements ModConfig { + DedicatedServerConfig dedicatedServerConfig, ClientConfig clientConfig) implements ModConfig { public static final MapCodec TYPE_CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( DisenchantConfig.CODEC.fieldOf("disenchant_to_book").forGetter(GrindEnchantmentsV2Config::disenchant), MoveConfig.CODEC.fieldOf("move_enchantments").forGetter(GrindEnchantmentsV2Config::move), @@ -34,19 +45,27 @@ public record GrindEnchantmentsV2Config(DisenchantConfig disenchant, MoveConfig ClientConfig.CODEC.fieldOf("client_options").forGetter(GrindEnchantmentsV2Config::clientConfig) ).apply(instance, instance.stable(GrindEnchantmentsV2Config::new))); - public static final ModConfig.Type TYPE = new ModConfig.Type<>(2, TYPE_CODEC); + public static final Type TYPE = new Type<>(2, TYPE_CODEC); public static final GrindEnchantmentsV2Config DEFAULT = new GrindEnchantmentsV2Config(DisenchantConfig.DEFAULT, MoveConfig.DEFAULT, false, DedicatedServerConfig.DEFAULT, ClientConfig.DEFAULT); @Override - public Type type() { + public Type type() { return TYPE; } @Override - public GrindEnchantmentsV2Config latest() { - return this; + public GrindEnchantmentsV3Config latest() { + return new GrindEnchantmentsV3Config( + new DisenchantConfig(this.disenchant.enabled(), this.disenchant.consumeItem(), + new FilterCostFunction(this.disenchant.costFunction())), + new MoveConfig(this.move.enabled(), + new FilterCostFunction(this.move.costFunction())), + new ResetRepairCostConfig(false, ResetRepairCostConfig.DEFAULT.catalystItems(), ResetRepairCostConfig.DEFAULT.requiresEnchantment(), ResetRepairCostConfig.DEFAULT.costFunction()), + new FilterConfig(true, FilterConfig.ItemConfig.DEFAULT, FilterConfig.EnchantmentConfig.DEFAULT, + this.allowCurses ? FilterAction.ALLOW : FilterAction.IGNORE), + this.dedicatedServerConfig, this.clientConfig); } @Override diff --git a/src/main/java/de/mschae23/grindenchantments/cost/AverageCountCostFunction.java b/src/main/java/de/mschae23/grindenchantments/cost/AverageCountCostFunction.java index 488b103..32e4284 100644 --- a/src/main/java/de/mschae23/grindenchantments/cost/AverageCountCostFunction.java +++ b/src/main/java/de/mschae23/grindenchantments/cost/AverageCountCostFunction.java @@ -23,6 +23,7 @@ import net.minecraft.registry.RegistryWrapper; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.config.FilterConfig; public record AverageCountCostFunction(CostFunction function) implements CostFunction { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( @@ -30,9 +31,9 @@ public record AverageCountCostFunction(CostFunction function) implements CostFun ).apply(instance, instance.stable(AverageCountCostFunction::new))); @Override - public double getCost(ItemEnchantmentsComponent enchantments, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup) { - double cost = this.function.getCost(enchantments, allowCurses, wrapperLookup); - long count = enchantments.getEnchantments().stream().filter(entry -> allowCurses || !entry.value().isCursed()).count(); + public double getCost(ItemEnchantmentsComponent enchantments, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup) { + double cost = this.function.getCost(enchantments, filter, wrapperLookup); + long count = enchantments.getEnchantments().size(); if (count == 0) { return cost; diff --git a/src/main/java/de/mschae23/grindenchantments/cost/CostFunction.java b/src/main/java/de/mschae23/grindenchantments/cost/CostFunction.java index 762b26f..a853786 100644 --- a/src/main/java/de/mschae23/grindenchantments/cost/CostFunction.java +++ b/src/main/java/de/mschae23/grindenchantments/cost/CostFunction.java @@ -22,12 +22,13 @@ import net.minecraft.component.type.ItemEnchantmentsComponent; import net.minecraft.registry.RegistryWrapper; import com.mojang.serialization.Codec; +import de.mschae23.grindenchantments.config.FilterConfig; import de.mschae23.grindenchantments.registry.GrindEnchantmentsRegistries; public interface CostFunction { Codec TYPE_CODEC = GrindEnchantmentsRegistries.COST_FUNCTION.getCodec().dispatch(CostFunction::getType, CostFunctionType::codec); - double getCost(ItemEnchantmentsComponent enchantments, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup); + double getCost(ItemEnchantmentsComponent enchantments, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup); CostFunctionType getType(); } diff --git a/src/main/java/de/mschae23/grindenchantments/cost/CostFunctionType.java b/src/main/java/de/mschae23/grindenchantments/cost/CostFunctionType.java index f6c85ba..ce65e57 100644 --- a/src/main/java/de/mschae23/grindenchantments/cost/CostFunctionType.java +++ b/src/main/java/de/mschae23/grindenchantments/cost/CostFunctionType.java @@ -28,9 +28,10 @@ public interface CostFunctionType { CostFunctionType COUNT_ENCHANTMENTS = register("count_enchantments", CountEnchantmentsCostFunction.CODEC); CostFunctionType COUNT_LEVELS = register("count_levels", CountLevelsCostFunction.CODEC); CostFunctionType COUNT_MIN_POWER = register("count_min_power", CountMinPowerCostFunction.CODEC); + CostFunctionType AVERAGE_COUNT = register("average_count", AverageCountCostFunction.CODEC); CostFunctionType FIRST_ENCHANTMENT = register("first_enchantment", FirstEnchantmentCostFunction.CODEC); CostFunctionType TRANSFORM = register("transform", TransformCostFunction.CODEC); - CostFunctionType AVERAGE_COUNT = register("average_count", AverageCountCostFunction.CODEC); + CostFunctionType FILTER = register("filter", FilterCostFunction.CODEC); MapCodec codec(); diff --git a/src/main/java/de/mschae23/grindenchantments/cost/CountEnchantmentsCostFunction.java b/src/main/java/de/mschae23/grindenchantments/cost/CountEnchantmentsCostFunction.java index 64da2a9..dc3b414 100644 --- a/src/main/java/de/mschae23/grindenchantments/cost/CountEnchantmentsCostFunction.java +++ b/src/main/java/de/mschae23/grindenchantments/cost/CountEnchantmentsCostFunction.java @@ -22,14 +22,15 @@ import net.minecraft.component.type.ItemEnchantmentsComponent; import net.minecraft.registry.RegistryWrapper; import com.mojang.serialization.MapCodec; +import de.mschae23.grindenchantments.config.FilterConfig; public class CountEnchantmentsCostFunction implements CostFunction { public static final CountEnchantmentsCostFunction INSTANCE = new CountEnchantmentsCostFunction(); public static final MapCodec CODEC = MapCodec.unit(() -> INSTANCE); @Override - public double getCost(ItemEnchantmentsComponent enchantments, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup) { - return (double) enchantments.getEnchantments().stream().filter(entry -> allowCurses || !entry.value().isCursed()).count(); + public double getCost(ItemEnchantmentsComponent enchantments, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup) { + return enchantments.getEnchantments().size(); } @Override diff --git a/src/main/java/de/mschae23/grindenchantments/cost/CountLevelsCostFunction.java b/src/main/java/de/mschae23/grindenchantments/cost/CountLevelsCostFunction.java index 4108f59..2966a5b 100644 --- a/src/main/java/de/mschae23/grindenchantments/cost/CountLevelsCostFunction.java +++ b/src/main/java/de/mschae23/grindenchantments/cost/CountLevelsCostFunction.java @@ -24,6 +24,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.config.FilterConfig; public record CountLevelsCostFunction(double normalFactor, double treasureFactor) implements CostFunction { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( @@ -32,9 +33,8 @@ public record CountLevelsCostFunction(double normalFactor, double treasureFactor ).apply(instance, instance.stable(CountLevelsCostFunction::new))); @Override - public double getCost(ItemEnchantmentsComponent enchantments, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup) { + public double getCost(ItemEnchantmentsComponent enchantments, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup) { return enchantments.getEnchantmentsMap().stream() - .filter(entry -> allowCurses || !entry.getKey().value().isCursed()) .mapToDouble(entry -> (double) entry.getIntValue() * (entry.getKey().value().isTreasure() ? this.treasureFactor : this.normalFactor)) .sum(); } diff --git a/src/main/java/de/mschae23/grindenchantments/cost/CountMinPowerCostFunction.java b/src/main/java/de/mschae23/grindenchantments/cost/CountMinPowerCostFunction.java index 0f71290..e7c2069 100644 --- a/src/main/java/de/mschae23/grindenchantments/cost/CountMinPowerCostFunction.java +++ b/src/main/java/de/mschae23/grindenchantments/cost/CountMinPowerCostFunction.java @@ -22,15 +22,15 @@ import net.minecraft.component.type.ItemEnchantmentsComponent; import net.minecraft.registry.RegistryWrapper; import com.mojang.serialization.MapCodec; +import de.mschae23.grindenchantments.config.FilterConfig; public class CountMinPowerCostFunction implements CostFunction { public static final CountMinPowerCostFunction INSTANCE = new CountMinPowerCostFunction(); public static final MapCodec CODEC = MapCodec.unit(() -> INSTANCE); @Override - public double getCost(ItemEnchantmentsComponent enchantments, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup) { + public double getCost(ItemEnchantmentsComponent enchantments, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup) { return enchantments.getEnchantmentsMap().stream() - .filter(entry -> allowCurses || !entry.getKey().value().isCursed()) .mapToDouble(entry -> entry.getKey().value().getMinPower(entry.getIntValue())) .sum(); } diff --git a/src/main/java/de/mschae23/grindenchantments/cost/FilterCostFunction.java b/src/main/java/de/mschae23/grindenchantments/cost/FilterCostFunction.java new file mode 100644 index 0000000..ad4a57f --- /dev/null +++ b/src/main/java/de/mschae23/grindenchantments/cost/FilterCostFunction.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 mschae23 + * + * This file is part of Grind enchantments. + * + * Grind enchantments is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package de.mschae23.grindenchantments.cost; + +import net.minecraft.component.type.ItemEnchantmentsComponent; +import net.minecraft.registry.RegistryWrapper; +import com.mojang.serialization.MapCodec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.config.FilterConfig; + +public record FilterCostFunction(CostFunction function) implements CostFunction { + public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( + CostFunction.TYPE_CODEC.fieldOf("function").forGetter(FilterCostFunction::function) + ).apply(instance, instance.stable(FilterCostFunction::new))); + + @Override + public double getCost(ItemEnchantmentsComponent enchantments, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup) { + return this.function.getCost(filter.filter(enchantments), filter, wrapperLookup); + } + + @Override + public CostFunctionType getType() { + return CostFunctionType.FILTER; + } +} diff --git a/src/main/java/de/mschae23/grindenchantments/cost/FirstEnchantmentCostFunction.java b/src/main/java/de/mschae23/grindenchantments/cost/FirstEnchantmentCostFunction.java index 14607ad..8865811 100644 --- a/src/main/java/de/mschae23/grindenchantments/cost/FirstEnchantmentCostFunction.java +++ b/src/main/java/de/mschae23/grindenchantments/cost/FirstEnchantmentCostFunction.java @@ -25,6 +25,7 @@ import net.minecraft.registry.entry.RegistryEntry; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.config.FilterConfig; import de.mschae23.grindenchantments.impl.MoveOperation; import it.unimi.dsi.fastutil.objects.ObjectIntPair; @@ -34,8 +35,8 @@ public record FirstEnchantmentCostFunction(CostFunction delegate) implements Cos ).apply(instance, instance.stable(FirstEnchantmentCostFunction::new))); @Override - public double getCost(ItemEnchantmentsComponent enchantments, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup) { - ObjectIntPair> firstEnchantment = MoveOperation.getFirstEnchantment(enchantments, allowCurses, wrapperLookup); + public double getCost(ItemEnchantmentsComponent enchantments, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup) { + ObjectIntPair> firstEnchantment = MoveOperation.getFirstEnchantment(enchantments, wrapperLookup); if (firstEnchantment == null) { return 1.0; @@ -43,7 +44,7 @@ public double getCost(ItemEnchantmentsComponent enchantments, boolean allowCurse ItemEnchantmentsComponent.Builder builder = new ItemEnchantmentsComponent.Builder(ItemEnchantmentsComponent.DEFAULT); builder.add(firstEnchantment.left().value(), firstEnchantment.rightInt()); - return this.delegate.getCost(builder.build(), allowCurses, wrapperLookup); + return this.delegate.getCost(builder.build(), filter, wrapperLookup); } } diff --git a/src/main/java/de/mschae23/grindenchantments/cost/TransformCostFunction.java b/src/main/java/de/mschae23/grindenchantments/cost/TransformCostFunction.java index c6c20c8..0a86265 100644 --- a/src/main/java/de/mschae23/grindenchantments/cost/TransformCostFunction.java +++ b/src/main/java/de/mschae23/grindenchantments/cost/TransformCostFunction.java @@ -24,6 +24,7 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; +import de.mschae23.grindenchantments.config.FilterConfig; public record TransformCostFunction(CostFunction function, double factor, double offset) implements CostFunction { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec(instance -> instance.group( @@ -33,8 +34,8 @@ public record TransformCostFunction(CostFunction function, double factor, double ).apply(instance, instance.stable(TransformCostFunction::new))); @Override - public double getCost(ItemEnchantmentsComponent enchantments, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup) { - return (this.function.getCost(enchantments, allowCurses, wrapperLookup)) * this.factor + this.offset; + public double getCost(ItemEnchantmentsComponent enchantments, FilterConfig filter, RegistryWrapper.WrapperLookup wrapperLookup) { + return (this.function.getCost(enchantments, filter, wrapperLookup)) * this.factor + this.offset; } @Override diff --git a/src/main/java/de/mschae23/grindenchantments/impl/DisenchantOperation.java b/src/main/java/de/mschae23/grindenchantments/impl/DisenchantOperation.java index 616d2a3..43622bb 100644 --- a/src/main/java/de/mschae23/grindenchantments/impl/DisenchantOperation.java +++ b/src/main/java/de/mschae23/grindenchantments/impl/DisenchantOperation.java @@ -22,21 +22,20 @@ import java.util.function.IntSupplier; import net.minecraft.component.DataComponentTypes; import net.minecraft.component.type.ItemEnchantmentsComponent; -import net.minecraft.enchantment.Enchantment; import net.minecraft.enchantment.EnchantmentHelper; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.Inventory; import net.minecraft.item.ItemStack; import net.minecraft.item.Items; import net.minecraft.registry.RegistryWrapper; -import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.screen.AnvilScreenHandler; import de.mschae23.grindenchantments.GrindEnchantments; import de.mschae23.grindenchantments.GrindEnchantmentsMod; -import de.mschae23.grindenchantments.config.GrindEnchantmentsV2Config; +import de.mschae23.grindenchantments.config.FilterAction; +import de.mschae23.grindenchantments.config.FilterConfig; +import de.mschae23.grindenchantments.config.GrindEnchantmentsV3Config; import de.mschae23.grindenchantments.event.ApplyLevelCostEvent; import de.mschae23.grindenchantments.event.GrindstoneEvents; -import it.unimi.dsi.fastutil.objects.Object2IntMap; import org.jetbrains.annotations.NotNull; public class DisenchantOperation implements GrindstoneEvents.CanInsert, GrindstoneEvents.UpdateResult, GrindstoneEvents.CanTakeResult, GrindstoneEvents.TakeResult, GrindstoneEvents.LevelCost { @@ -53,20 +52,20 @@ public boolean canInsert(ItemStack stack, ItemStack other, int slotId) { ItemStack enchantedItemStack = input1.hasEnchantments() ? input1 : input2; - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); - return transferEnchantmentsToBook(enchantedItemStack, config.allowCurses()); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); + return transferEnchantmentsToBook(enchantedItemStack, config.filter()); } @Override public boolean canTakeResult(ItemStack input1, ItemStack input2, PlayerEntity player, RegistryWrapper.WrapperLookup wrapperLookup) { if (isDisenchantOperation(input1, input2)) { - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); boolean stack1Book = input1.getItem() == Items.BOOK; ItemStack enchantedItemStack = stack1Book ? input2 : input1; return canTakeResult(input1, input2, () -> - GrindEnchantments.getLevelCost(enchantedItemStack, config.disenchant().costFunction(), config.allowCurses(), wrapperLookup), player); + GrindEnchantments.getLevelCost(enchantedItemStack, config.disenchant().costFunction(), config.filter(), wrapperLookup), player); } return true; @@ -78,19 +77,19 @@ public boolean onTakeResult(ItemStack input1, ItemStack input2, ItemStack result return false; } - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); boolean stack1Book = input1.getItem() == Items.BOOK; ItemStack enchantedItemStack = stack1Book ? input2 : input1; ItemStack bookItemStack = stack1Book ? input1 : input2; if (!player.getAbilities().creativeMode) { - int cost = debugLevelCost("onTakeResult", GrindEnchantments.getLevelCost(enchantedItemStack, config.disenchant().costFunction(), config.allowCurses(), wrapperLookup)); + int cost = debugLevelCost("onTakeResult", GrindEnchantments.getLevelCost(enchantedItemStack, config.disenchant().costFunction(), config.filter(), wrapperLookup)); ApplyLevelCostEvent.EVENT.invoker().applyLevelCost(cost, player); } input.setStack(stack1Book ? 1 : 0, config.disenchant().consumeItem() ? - ItemStack.EMPTY : grind(enchantedItemStack, config.allowCurses())); + ItemStack.EMPTY : grind(enchantedItemStack, config.filter())); if (bookItemStack.getCount() == 1) input.setStack(stack1Book ? 0 : 1, ItemStack.EMPTY); @@ -106,11 +105,11 @@ public boolean onTakeResult(ItemStack input1, ItemStack input2, ItemStack result @Override public int getLevelCost(ItemStack input1, ItemStack input2, PlayerEntity player, RegistryWrapper.WrapperLookup wrapperLookup) { if (isDisenchantOperation(input1, input2)) { - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); boolean stack1Book = input1.getItem() == Items.BOOK; ItemStack enchantedItemStack = stack1Book ? input2 : input1; - return debugLevelCost("getLevelCost", GrindEnchantments.getLevelCost(enchantedItemStack, config.disenchant().costFunction(), config.allowCurses(), wrapperLookup)); + return debugLevelCost("getLevelCost", GrindEnchantments.getLevelCost(enchantedItemStack, config.disenchant().costFunction(), config.filter(), wrapperLookup)); } return -1; @@ -134,30 +133,37 @@ public static boolean canTakeResult(@SuppressWarnings("unused") ItemStack input1 return player.getAbilities().creativeMode || player.experienceLevel >= cost.getAsInt(); } - public static ItemStack transferEnchantmentsToBook(ItemStack source, boolean allowCurses) { - ItemStack itemStack = new ItemStack(Items.ENCHANTED_BOOK); - itemStack.set(DataComponentTypes.STORED_ENCHANTMENTS, ItemEnchantmentsComponent.DEFAULT); + public static ItemStack transferEnchantmentsToBook(ItemStack source, FilterConfig filter) { + if (filter.enabled() && filter.item().action() != FilterAction.IGNORE + && (filter.item().action() == FilterAction.DENY) == filter.item().items().contains(source.getRegistryEntry())) { + return ItemStack.EMPTY; + } - Object2IntMap> map = GrindEnchantments.getEnchantments(source, allowCurses); + ItemEnchantmentsComponent enchantments = GrindEnchantments.getEnchantments(source, filter); - if (map.isEmpty()) + if (enchantments.isEmpty()) return ItemStack.EMPTY; - for (Object2IntMap.Entry> entry : map.object2IntEntrySet()) { - EnchantmentHelper.apply(itemStack, builder -> builder.add(entry.getKey().value(), entry.getIntValue())); + int repairCost = 0; + + for(int i = 0; i < enchantments.getSize(); i++) { + repairCost = AnvilScreenHandler.getNextCost(repairCost); } - return itemStack; + ItemStack book = new ItemStack(Items.ENCHANTED_BOOK); + book.set(DataComponentTypes.STORED_ENCHANTMENTS, enchantments); + book.set(DataComponentTypes.REPAIR_COST, repairCost); + return book; } - private static ItemStack grind(ItemStack item, boolean allowCurses) { - ItemStack item2 = item.copy(); - - ItemEnchantmentsComponent enchantments = EnchantmentHelper.apply(item2, components -> - components.remove(enchantment -> allowCurses || !enchantment.value().isCursed())); + private static ItemStack grind(ItemStack stack, FilterConfig filter) { + ItemStack stack2 = stack.copy(); + ItemEnchantmentsComponent enchantments = filter.filterReversed(stack2.getOrDefault(EnchantmentHelper.getEnchantmentsComponentType(stack2), + ItemEnchantmentsComponent.DEFAULT)); + stack2.set(EnchantmentHelper.getEnchantmentsComponentType(stack2), enchantments); - if (item2.isOf(Items.ENCHANTED_BOOK) && enchantments.isEmpty()) { - item2 = item2.copyComponentsToNewStack(Items.BOOK, item2.getCount()); + if (stack2.isOf(Items.ENCHANTED_BOOK) && enchantments.isEmpty()) { + stack2 = stack2.copyComponentsToNewStack(Items.BOOK, stack2.getCount()); } int repairCost = 0; @@ -166,7 +172,7 @@ private static ItemStack grind(ItemStack item, boolean allowCurses) { repairCost = AnvilScreenHandler.getNextCost(repairCost); } - item2.set(DataComponentTypes.REPAIR_COST, repairCost); - return item2; + stack2.set(DataComponentTypes.REPAIR_COST, repairCost); + return stack2; } } diff --git a/src/main/java/de/mschae23/grindenchantments/impl/MoveOperation.java b/src/main/java/de/mschae23/grindenchantments/impl/MoveOperation.java index d46363b..37c1728 100644 --- a/src/main/java/de/mschae23/grindenchantments/impl/MoveOperation.java +++ b/src/main/java/de/mschae23/grindenchantments/impl/MoveOperation.java @@ -33,9 +33,12 @@ import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.registry.entry.RegistryEntryList; import net.minecraft.registry.tag.EnchantmentTags; +import net.minecraft.screen.AnvilScreenHandler; import de.mschae23.grindenchantments.GrindEnchantments; import de.mschae23.grindenchantments.GrindEnchantmentsMod; -import de.mschae23.grindenchantments.config.GrindEnchantmentsV2Config; +import de.mschae23.grindenchantments.config.FilterAction; +import de.mschae23.grindenchantments.config.FilterConfig; +import de.mschae23.grindenchantments.config.GrindEnchantmentsV3Config; import de.mschae23.grindenchantments.event.ApplyLevelCostEvent; import de.mschae23.grindenchantments.event.GrindstoneEvents; import it.unimi.dsi.fastutil.objects.Object2IntMap; @@ -55,9 +58,15 @@ public boolean canInsert(ItemStack stack, ItemStack other, int slotId) { return ItemStack.EMPTY; } - boolean allowCurses = GrindEnchantmentsMod.getConfig().allowCurses(); - ItemEnchantmentsComponent enchantments = EnchantmentHelper.getEnchantments(input1); - ObjectIntPair> firstEnchantment = getFirstEnchantment(enchantments, allowCurses, wrapperLookup); + FilterConfig filter = GrindEnchantmentsMod.getConfig().filter(); + + if (filter.enabled() && filter.item().action() != FilterAction.IGNORE + && (filter.item().action() == FilterAction.DENY) == filter.item().items().contains(input1.getRegistryEntry())) { + return ItemStack.EMPTY; + } + + ItemEnchantmentsComponent enchantments = GrindEnchantments.getEnchantments(input1, filter); + ObjectIntPair> firstEnchantment = getFirstEnchantment(enchantments, wrapperLookup); if (firstEnchantment == null) { return ItemStack.EMPTY; @@ -83,17 +92,24 @@ public boolean canInsert(ItemStack stack, ItemStack other, int slotId) { result = result.copyComponentsToNewStack(Items.ENCHANTED_BOOK, 1); } + int repairCost = 0; + + for(int i = 0; i < builder.getEnchantments().size(); i++) { + repairCost = AnvilScreenHandler.getNextCost(repairCost); + } + result.set(DataComponentTypes.STORED_ENCHANTMENTS, builder.build()); + result.set(DataComponentTypes.REPAIR_COST, repairCost); return result; } @Override public boolean canTakeResult(ItemStack input1, ItemStack input2, PlayerEntity player, RegistryWrapper.WrapperLookup wrapperLookup) { if (isMoveOperation(input1, input2)) { - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); return canTakeResult(input1, input2, () -> - GrindEnchantments.getLevelCost(input1, config.move().costFunction(), config.allowCurses(), wrapperLookup), player); + GrindEnchantments.getLevelCost(input1, config.move().costFunction(), config.filter(), wrapperLookup), player); } return true; @@ -105,11 +121,11 @@ public boolean onTakeResult(ItemStack input1, ItemStack input2, ItemStack result return false; } - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); - boolean allowCurses = config.allowCurses(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); + FilterConfig filter = config.filter(); ItemEnchantmentsComponent enchantments = EnchantmentHelper.getEnchantments(input1); - ObjectIntPair> firstEnchantment = getFirstEnchantment(enchantments, allowCurses, wrapperLookup); + ObjectIntPair> firstEnchantment = getFirstEnchantment(filter.filter(enchantments), wrapperLookup); if (firstEnchantment == null) { return false; @@ -120,6 +136,7 @@ public boolean onTakeResult(ItemStack input1, ItemStack input2, ItemStack result ItemStack resultingInput1 = new ItemStack(Items.ENCHANTED_BOOK); EnchantmentHelper.set(resultingInput1, builder.build()); + resultingInput1.set(DataComponentTypes.REPAIR_COST, AnvilScreenHandler.getNextCost(input1.getOrDefault(DataComponentTypes.REPAIR_COST, 0))); input.setStack(0, resultingInput1); @@ -132,7 +149,7 @@ public boolean onTakeResult(ItemStack input1, ItemStack input2, ItemStack result } if (!player.getAbilities().creativeMode) { - int cost = GrindEnchantments.getLevelCost(input1, config.move().costFunction(), allowCurses, wrapperLookup); + int cost = GrindEnchantments.getLevelCost(input1, config.move().costFunction(), filter, wrapperLookup); ApplyLevelCostEvent.EVENT.invoker().applyLevelCost(cost, player); } @@ -142,9 +159,9 @@ public boolean onTakeResult(ItemStack input1, ItemStack input2, ItemStack result @Override public int getLevelCost(ItemStack input1, ItemStack input2, PlayerEntity player, RegistryWrapper.WrapperLookup wrapperLookup) { if (isMoveOperation(input1, input2)) { - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); - return GrindEnchantments.getLevelCost(input1, config.move().costFunction(), config.allowCurses(), wrapperLookup); + return GrindEnchantments.getLevelCost(input1, config.move().costFunction(), config.filter(), wrapperLookup); } return -1; @@ -165,7 +182,11 @@ public static boolean canTakeResult(@SuppressWarnings("unused") ItemStack input1 } @Nullable - public static ObjectIntPair> getFirstEnchantment(ItemEnchantmentsComponent enchantments, boolean allowCurses, RegistryWrapper.WrapperLookup wrapperLookup) { + public static ObjectIntPair> getFirstEnchantment(ItemEnchantmentsComponent enchantments, RegistryWrapper.WrapperLookup wrapperLookup) { + if (enchantments.getSize() < 2) { + return null; + } + RegistryEntryList tooltipOrder = ItemEnchantmentsComponent.getTooltipOrderList(wrapperLookup, RegistryKeys.ENCHANTMENT, EnchantmentTags.TOOLTIP_ORDER); @Nullable @@ -174,32 +195,19 @@ public static ObjectIntPair> getFirstEnchantment(Item for (RegistryEntry entry : tooltipOrder) { int level = enchantments.enchantments.getInt(entry); - if (level > 0 && (allowCurses || !entry.value().isCursed())) { + if (level > 0) { firstEnchantment = ObjectIntPair.of(entry, level); break; } } - byte enchantmentCount = 0; - for (Object2IntMap.Entry> entry : enchantments.getEnchantmentsMap()) { - if (firstEnchantment == null && !tooltipOrder.contains(entry.getKey()) && (allowCurses || !entry.getKey().value().isCursed())) { + if (firstEnchantment == null && !tooltipOrder.contains(entry.getKey())) { firstEnchantment = ObjectIntPair.of(entry.getKey(), entry.getIntValue()); - } - - if (allowCurses || !entry.getKey().value().isCursed()) { - enchantmentCount += 1; - } - - if (enchantmentCount >= 2) { break; } } - if (enchantmentCount < 2) { - return null; - } - return firstEnchantment; } } diff --git a/src/main/java/de/mschae23/grindenchantments/impl/ResetRepairCostOperation.java b/src/main/java/de/mschae23/grindenchantments/impl/ResetRepairCostOperation.java new file mode 100644 index 0000000..cd27151 --- /dev/null +++ b/src/main/java/de/mschae23/grindenchantments/impl/ResetRepairCostOperation.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2024 mschae23 + * + * This file is part of Grind enchantments. + * + * Grind enchantments is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ + +package de.mschae23.grindenchantments.impl; + +import java.util.function.IntSupplier; +import net.minecraft.component.DataComponentTypes; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.registry.RegistryWrapper; +import de.mschae23.grindenchantments.GrindEnchantments; +import de.mschae23.grindenchantments.GrindEnchantmentsMod; +import de.mschae23.grindenchantments.config.FilterAction; +import de.mschae23.grindenchantments.config.FilterConfig; +import de.mschae23.grindenchantments.config.GrindEnchantmentsV3Config; +import de.mschae23.grindenchantments.config.ResetRepairCostConfig; +import de.mschae23.grindenchantments.event.ApplyLevelCostEvent; +import de.mschae23.grindenchantments.event.GrindstoneEvents; +import org.jetbrains.annotations.NotNull; + +public class ResetRepairCostOperation implements GrindstoneEvents.CanInsert, GrindstoneEvents.UpdateResult, GrindstoneEvents.CanTakeResult, GrindstoneEvents.TakeResult, GrindstoneEvents.LevelCost { + @Override + public boolean canInsert(ItemStack stack, ItemStack other, int slotId) { + ResetRepairCostConfig config = GrindEnchantmentsMod.getConfig().resetRepairCost(); + + return config.enabled() && slotId == 1 && config.catalystItems().contains(stack.getRegistryEntry()); + } + + @Override + public @NotNull ItemStack onUpdateResult(ItemStack input1, ItemStack input2, PlayerEntity player, RegistryWrapper.WrapperLookup wrapperLookup) { + if (!isResetRepairCostOperation(input1, input2)) { + return ItemStack.EMPTY; + } + + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); + FilterConfig filter = config.filter(); + + if (filter.enabled() && filter.item().action() != FilterAction.IGNORE + && (filter.item().action() == FilterAction.DENY) == filter.item().items().contains(input1.getRegistryEntry())) { + return ItemStack.EMPTY; + } + + if (input1.getOrDefault(DataComponentTypes.REPAIR_COST, 0) <= 0) { + return ItemStack.EMPTY; + } else if (config.resetRepairCost().requiresEnchantment() && !EnchantmentHelper.hasEnchantments(input1)) { + return ItemStack.EMPTY; + } + + ItemStack result = input1.copy(); + result.remove(DataComponentTypes.REPAIR_COST); + + return result; + } + + @Override + public boolean canTakeResult(ItemStack input1, ItemStack input2, PlayerEntity player, RegistryWrapper.WrapperLookup wrapperLookup) { + if (isResetRepairCostOperation(input1, input2)) { + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); + + return canTakeResult(input1, input2, () -> + GrindEnchantments.getLevelCost(input1, config.resetRepairCost().costFunction(), config.filter(), wrapperLookup), player); + } + + return true; + } + + @Override + public boolean onTakeResult(ItemStack input1, ItemStack input2, ItemStack resultStack, PlayerEntity player, Inventory input, RegistryWrapper.WrapperLookup wrapperLookup) { + if (!isResetRepairCostOperation(input1, input2)) { + return false; + } + + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); + FilterConfig filter = config.filter(); + + input.setStack(0, ItemStack.EMPTY); + + if (input2.getCount() == 1) + input.setStack(1, ItemStack.EMPTY); + else { + ItemStack newCatalystStack = input2.copy(); + newCatalystStack.setCount(input2.getCount() - 1); + input.setStack(1, newCatalystStack); + } + + if (!player.getAbilities().creativeMode) { + int cost = GrindEnchantments.getLevelCost(input1, config.resetRepairCost().costFunction(), filter, wrapperLookup); + ApplyLevelCostEvent.EVENT.invoker().applyLevelCost(cost, player); + } + + return true; + } + + @Override + public int getLevelCost(ItemStack input1, ItemStack input2, PlayerEntity player, RegistryWrapper.WrapperLookup wrapperLookup) { + if (isResetRepairCostOperation(input1, input2)) { + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); + + return GrindEnchantments.getLevelCost(input1, config.resetRepairCost().costFunction(), config.filter(), wrapperLookup); + } + + return -1; + } + + public static boolean isResetRepairCostOperation(ItemStack input1, ItemStack input2) { + ResetRepairCostConfig config = GrindEnchantmentsMod.getConfig().resetRepairCost(); + + if (!config.enabled()) + return false; + + return (input1.isDamageable() || EnchantmentHelper.canHaveEnchantments(input1)) + && !input2.isOf(Items.BOOK) && !input2.isOf(Items.ENCHANTED_BOOK) && !input2.isDamageable() && !input2.isOf(input1.getItem()) + && config.catalystItems().contains(input2.getRegistryEntry()); + } + + public static boolean canTakeResult(@SuppressWarnings("unused") ItemStack input1, @SuppressWarnings("unused") ItemStack input2, + IntSupplier cost, PlayerEntity player) { + return player.getAbilities().creativeMode || player.experienceLevel >= cost.getAsInt(); + } +} diff --git a/src/main/java/de/mschae23/grindenchantments/mixin/GrindstoneScreenHandlerMixin.java b/src/main/java/de/mschae23/grindenchantments/mixin/GrindstoneScreenHandlerMixin.java index 22c1241..e37264b 100644 --- a/src/main/java/de/mschae23/grindenchantments/mixin/GrindstoneScreenHandlerMixin.java +++ b/src/main/java/de/mschae23/grindenchantments/mixin/GrindstoneScreenHandlerMixin.java @@ -31,7 +31,7 @@ import net.minecraft.world.WorldEvents; import de.mschae23.grindenchantments.GrindEnchantments; import de.mschae23.grindenchantments.GrindEnchantmentsMod; -import de.mschae23.grindenchantments.config.GrindEnchantmentsV2Config; +import de.mschae23.grindenchantments.config.GrindEnchantmentsV3Config; import de.mschae23.grindenchantments.event.GrindstoneEvents; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -86,7 +86,7 @@ private void onGetOutputStack(ItemStack input1, ItemStack input2, CallbackInfoRe @Inject(method = "quickMove", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/GrindstoneScreenHandler;insertItem(Lnet/minecraft/item/ItemStack;IIZ)Z", ordinal = 0), locals = LocalCapture.CAPTURE_FAILHARD) private void onInsertResultItem(PlayerEntity player, int index, CallbackInfoReturnable cir, ItemStack itemStack1, Slot slot, ItemStack itemStack2) { - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); if (config.dedicatedServerConfig().alternativeCostDisplay()) { GrindEnchantments.removeLevelCostNbt(itemStack2); diff --git a/src/main/java/de/mschae23/grindenchantments/mixin/ScreenHandlerMixin.java b/src/main/java/de/mschae23/grindenchantments/mixin/ScreenHandlerMixin.java index 618de91..0798dab 100644 --- a/src/main/java/de/mschae23/grindenchantments/mixin/ScreenHandlerMixin.java +++ b/src/main/java/de/mschae23/grindenchantments/mixin/ScreenHandlerMixin.java @@ -27,7 +27,7 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; import de.mschae23.grindenchantments.GrindEnchantments; import de.mschae23.grindenchantments.GrindEnchantmentsMod; -import de.mschae23.grindenchantments.config.GrindEnchantmentsV2Config; +import de.mschae23.grindenchantments.config.GrindEnchantmentsV3Config; import de.mschae23.grindenchantments.item.GrindEnchantmentsDataComponent; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; @@ -37,7 +37,7 @@ public class ScreenHandlerMixin { @WrapOperation(method = "sendContentUpdates", at = @At(value = "INVOKE", target = "Lcom/google/common/base/Suppliers;memoize(Lcom/google/common/base/Supplier;)Lcom/google/common/base/Supplier;", remap = false)) private com.google.common.base.Supplier addLoreOnSendUpdates(com.google.common.base.Supplier delegate, Operation> original) { - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); if (!config.dedicatedServerConfig().alternativeCostDisplay()) { return original.call(delegate); @@ -61,7 +61,7 @@ private com.google.common.base.Supplier addLoreOnSendUpdates(com.goog @WrapOperation(method = "updateToClient", at = @At(value = "INVOKE", target = "Lnet/minecraft/screen/slot/Slot;getStack()Lnet/minecraft/item/ItemStack;")) private ItemStack addLoreOnUpdateToClient(Slot slot, Operation original) { - GrindEnchantmentsV2Config config = GrindEnchantmentsMod.getConfig(); + GrindEnchantmentsV3Config config = GrindEnchantmentsMod.getConfig(); ItemStack stack = original.call(slot).copy(); if (!config.dedicatedServerConfig().alternativeCostDisplay()) { diff --git a/src/main/resources/grindenchantments.accesswidener b/src/main/resources/grindenchantments.accesswidener index b7372b0..dd2b009 100644 --- a/src/main/resources/grindenchantments.accesswidener +++ b/src/main/resources/grindenchantments.accesswidener @@ -4,3 +4,4 @@ accessible field net/minecraft/screen/GrindstoneScreenHandler result Lnet/minecr accessible field net/minecraft/component/type/ItemEnchantmentsComponent enchantments Lit/unimi/dsi/fastutil/objects/Object2IntOpenHashMap; accessible method net/minecraft/component/type/ItemEnchantmentsComponent getTooltipOrderList (Lnet/minecraft/registry/RegistryWrapper$WrapperLookup;Lnet/minecraft/registry/RegistryKey;Lnet/minecraft/registry/tag/TagKey;)Lnet/minecraft/registry/entry/RegistryEntryList; +accessible method net/minecraft/enchantment/EnchantmentHelper getEnchantmentsComponentType (Lnet/minecraft/item/ItemStack;)Lnet/minecraft/component/DataComponentType;