From f3d22187f8c79f915c9e77805d7ca69ca6090881 Mon Sep 17 00:00:00 2001 From: RubixDev Date: Wed, 29 Nov 2023 10:12:34 +0800 Subject: [PATCH] feat: add Vacuum enchantment closes #22 --- README.md | 15 +++++- .../de/rubixdev/enchantedshulkers/Mod.java | 3 ++ .../de/rubixdev/enchantedshulkers/Utils.java | 2 + .../enchantedshulkers/config/WorldConfig.java | 21 ++++++-- .../enchantment/RefillEnchantment.java | 4 +- .../enchantment/SiphonEnchantment.java | 23 ++++++--- .../enchantment/VacuumEnchantment.java | 50 +++++++++++++++++++ .../mixin/PlayerInventoryMixin.java | 3 ++ .../assets/enchantedshulkers/lang/de_de.yml | 8 ++- .../assets/enchantedshulkers/lang/en_us.yml | 8 ++- .../assets/enchantedshulkers/lang/zh_cn.yml | 8 ++- 11 files changed, 129 insertions(+), 16 deletions(-) create mode 100644 src/main/java/de/rubixdev/enchantedshulkers/enchantment/VacuumEnchantment.java diff --git a/README.md b/README.md index 15c4523..c023c36 100644 --- a/README.md +++ b/README.md @@ -47,6 +47,16 @@ from an enchanted container as long as the used stack was held in one of the hands (see [configuration](#configuration)). Again, the container must be inside your inventory. +### Vacuum + +The Vacuum enchantment doesn't generate by default making it unobtainable in +survival. To change that, set the `generateVacuum` option to `true` (and +optionally disable Siphon by setting `generateSiphon` to `false`). Its behavior +is very similar to that of the Siphon enchantment, with the key difference that +it doesn't require the same item to already be present in the enchanted +container. This means a container enchanted with Vacuum will take all items you +pick up as long as it has space to do so. + ## A note on Resource Packs When using EnchantedShulkers with a resource pack that alters the look of @@ -118,7 +128,10 @@ command in game. Below is a list of available options. | `coloredNames` | `true`, `false` | `false` | Show the names of placed enchanted containers in aqua color. This applies to all players | | `creativeSiphon` | `true`, `false` | `false` | Enable the Siphon enchantment for creative players | | `creativeRefill` | `true`, `false` | `false` | Enable the Refill enchantment for creative players | -| `generateBooks` | `true`, `false` | `true` | Make the enchantments obtainable in survival by allowing enchanted books to generate with them | +| `creativeVacuum` | `true`, `false` | `false` | Enable the Vacuum enchantment for creative players | +| `generateSiphon` | `true`, `false` | `true` | Make the Siphon enchantment obtainable in survival by allowing enchanted books to generate with it | +| `generateRefill` | `true`, `false` | `true` | Make the Refill enchantment obtainable in survival by allowing enchanted books to generate with it | +| `generateVacuum` | `true`, `false` | `false` | Make the Vacuum enchantment obtainable in survival by allowing enchanted books to generate with it | | `nestedContainers` | `true`, `false` | `true` | Search containers recursively up to 256 levels deep (e.g, search through Shulker Boxes in an Ender Chest) | ## For Mod Developers diff --git a/src/main/java/de/rubixdev/enchantedshulkers/Mod.java b/src/main/java/de/rubixdev/enchantedshulkers/Mod.java index 3b2efe0..2146401 100644 --- a/src/main/java/de/rubixdev/enchantedshulkers/Mod.java +++ b/src/main/java/de/rubixdev/enchantedshulkers/Mod.java @@ -8,6 +8,7 @@ import de.rubixdev.enchantedshulkers.config.WorldConfig; import de.rubixdev.enchantedshulkers.enchantment.RefillEnchantment; import de.rubixdev.enchantedshulkers.enchantment.SiphonEnchantment; +import de.rubixdev.enchantedshulkers.enchantment.VacuumEnchantment; import de.rubixdev.enchantedshulkers.interfaces.HasClientMod; import de.rubixdev.enchantedshulkers.interfaces.InventoryState; import net.fabricmc.api.ModInitializer; @@ -67,6 +68,7 @@ public class Mod implements ModInitializer { public static final SiphonEnchantment SIPHON_ENCHANTMENT = new SiphonEnchantment(); public static final RefillEnchantment REFILL_ENCHANTMENT = new RefillEnchantment(); + public static final VacuumEnchantment VACUUM_ENCHANTMENT = new VacuumEnchantment(); public static final Identifier CLIENT_INSTALLED_PACKET_ID = new Identifier(MOD_ID, "client_installed"); public static final Identifier INVENTORY_OPEN_PACKET_ID = new Identifier(MOD_ID, "inventory_open"); @@ -76,6 +78,7 @@ public class Mod implements ModInitializer { public void onInitialize() { Registry.register(Registries.ENCHANTMENT, new Identifier(MOD_ID, "siphon"), SIPHON_ENCHANTMENT); Registry.register(Registries.ENCHANTMENT, new Identifier(MOD_ID, "refill"), REFILL_ENCHANTMENT); + Registry.register(Registries.ENCHANTMENT, new Identifier(MOD_ID, "vacuum"), VACUUM_ENCHANTMENT); // Add enchanted_ender_chest data pack when enabled in config FabricLoader.getInstance() diff --git a/src/main/java/de/rubixdev/enchantedshulkers/Utils.java b/src/main/java/de/rubixdev/enchantedshulkers/Utils.java index 37e4746..c9f1200 100644 --- a/src/main/java/de/rubixdev/enchantedshulkers/Utils.java +++ b/src/main/java/de/rubixdev/enchantedshulkers/Utils.java @@ -43,6 +43,8 @@ private static List getContainers( List inventory, ServerPlayerEntity player, Enchantment enchantment, int recursionDepth) { List out = new ArrayList<>(); for (ItemStack stack : inventory) { + // TODO: technically a vacuum shulker box inside a siphon ender chest should also be returned here, + // but unless someone complains i can't be bothered :P if (canEnchant(stack) && EnchantmentHelper.getLevel(enchantment, stack) > 0 && !(visitedEnderChest && stack.isOf(Items.ENDER_CHEST))) { diff --git a/src/main/java/de/rubixdev/enchantedshulkers/config/WorldConfig.java b/src/main/java/de/rubixdev/enchantedshulkers/config/WorldConfig.java index a367205..2ae8e9c 100644 --- a/src/main/java/de/rubixdev/enchantedshulkers/config/WorldConfig.java +++ b/src/main/java/de/rubixdev/enchantedshulkers/config/WorldConfig.java @@ -146,8 +146,20 @@ public static boolean creativeRefill() { return inner.creativeRefill; } - public static boolean generateBooks() { - return inner.generateBooks; + public static boolean creativeVacuum() { + return inner.creativeVacuum; + } + + public static boolean generateRefill() { + return inner.generateRefill; + } + + public static boolean generateSiphon() { + return inner.generateSiphon; + } + + public static boolean generateVacuum() { + return inner.generateVacuum; } public static boolean nestedContainers() { @@ -161,7 +173,10 @@ private static class Inner { boolean coloredNames = false; boolean creativeSiphon = false; boolean creativeRefill = false; - boolean generateBooks = true; + boolean creativeVacuum = false; + boolean generateRefill = true; + boolean generateSiphon = true; + boolean generateVacuum = false; boolean nestedContainers = true; } } diff --git a/src/main/java/de/rubixdev/enchantedshulkers/enchantment/RefillEnchantment.java b/src/main/java/de/rubixdev/enchantedshulkers/enchantment/RefillEnchantment.java index 8b5dee3..8e33467 100644 --- a/src/main/java/de/rubixdev/enchantedshulkers/enchantment/RefillEnchantment.java +++ b/src/main/java/de/rubixdev/enchantedshulkers/enchantment/RefillEnchantment.java @@ -35,12 +35,12 @@ public boolean isTreasure() { @Override public boolean isAvailableForEnchantedBookOffer() { - return WorldConfig.generateBooks(); + return WorldConfig.generateRefill(); } @Override public boolean isAvailableForRandomSelection() { - return WorldConfig.generateBooks(); + return WorldConfig.generateRefill(); } public static void onPlayerTick( diff --git a/src/main/java/de/rubixdev/enchantedshulkers/enchantment/SiphonEnchantment.java b/src/main/java/de/rubixdev/enchantedshulkers/enchantment/SiphonEnchantment.java index d1552c6..6455cb8 100644 --- a/src/main/java/de/rubixdev/enchantedshulkers/enchantment/SiphonEnchantment.java +++ b/src/main/java/de/rubixdev/enchantedshulkers/enchantment/SiphonEnchantment.java @@ -34,18 +34,21 @@ public boolean isTreasure() { @Override public boolean isAvailableForEnchantedBookOffer() { - return WorldConfig.generateBooks(); + return WorldConfig.generateSiphon(); } @Override public boolean isAvailableForRandomSelection() { - return WorldConfig.generateBooks(); + return WorldConfig.generateSiphon(); } public static boolean onItemPickup(ServerPlayerEntity player, ItemStack stack) { if (player.isCreative() && !WorldConfig.creativeSiphon()) return false; + return onItemPickup(player, stack, Mod.SIPHON_ENCHANTMENT, true); + } - List containerSlots = Utils.getContainers(player, Mod.SIPHON_ENCHANTMENT); + public static boolean onItemPickup(ServerPlayerEntity player, ItemStack stack, Enchantment enchantment, boolean requireStack) { + List containerSlots = Utils.getContainers(player, enchantment); boolean usedSiphon = false; for (ItemStack container : containerSlots) { @@ -53,9 +56,10 @@ public static boolean onItemPickup(ServerPlayerEntity player, ItemStack stack) { DefaultedList containerInventory = Utils.getContainerInventory(container, player); boolean updateContainer = false; - for (ItemStack innerStack : containerInventory) { - if (innerStack.isEmpty()) continue; - if (trySiphonStack(stack, innerStack)) { + for (int i = 0; i < containerInventory.toArray().length; i++) { + ItemStack innerStack = containerInventory.get(i); + if (innerStack.isEmpty() && requireStack) continue; + if (trySiphonStack(stack, innerStack, containerInventory, i)) { updateContainer = true; if (stack.isEmpty()) break; } @@ -68,7 +72,12 @@ public static boolean onItemPickup(ServerPlayerEntity player, ItemStack stack) { return usedSiphon; } - static boolean trySiphonStack(ItemStack from, ItemStack to) { + static boolean trySiphonStack(ItemStack from, ItemStack to, DefaultedList containerInventory, int toIndex) { + if (to.isEmpty()) { + containerInventory.set(toIndex, from.copyAndEmpty()); + return true; + } + if (!ItemStack.canCombine(from, to)) return false; int transferCount = Math.min(to.getMaxCount() - to.getCount(), from.getCount()); if (transferCount <= 0) return false; diff --git a/src/main/java/de/rubixdev/enchantedshulkers/enchantment/VacuumEnchantment.java b/src/main/java/de/rubixdev/enchantedshulkers/enchantment/VacuumEnchantment.java new file mode 100644 index 0000000..b3695fd --- /dev/null +++ b/src/main/java/de/rubixdev/enchantedshulkers/enchantment/VacuumEnchantment.java @@ -0,0 +1,50 @@ +package de.rubixdev.enchantedshulkers.enchantment; + +import de.rubixdev.enchantedshulkers.Mod; +import de.rubixdev.enchantedshulkers.Utils; +import de.rubixdev.enchantedshulkers.config.WorldConfig; +import net.minecraft.enchantment.Enchantment; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.collection.DefaultedList; + +import java.util.List; + +public class VacuumEnchantment extends Enchantment { + public VacuumEnchantment() { + super(Rarity.RARE, Mod.PORTABLE_CONTAINER_TARGET, new EquipmentSlot[] { + EquipmentSlot.MAINHAND, EquipmentSlot.OFFHAND + }); + } + + @Override + public int getMinPower(int level) { + return level * 25; + } + + @Override + public int getMaxPower(int level) { + return getMinPower(level) + 50; + } + + @Override + public boolean isTreasure() { + return true; + } + + @Override + public boolean isAvailableForEnchantedBookOffer() { + return WorldConfig.generateVacuum(); + } + + @Override + public boolean isAvailableForRandomSelection() { + return WorldConfig.generateVacuum(); + } + + public static boolean onItemPickup(ServerPlayerEntity player, ItemStack stack) { + if (player.isCreative() && !WorldConfig.creativeVacuum()) return false; + return SiphonEnchantment.onItemPickup(player, stack, Mod.VACUUM_ENCHANTMENT, false); + } +} diff --git a/src/main/java/de/rubixdev/enchantedshulkers/mixin/PlayerInventoryMixin.java b/src/main/java/de/rubixdev/enchantedshulkers/mixin/PlayerInventoryMixin.java index e93e108..b9800a7 100644 --- a/src/main/java/de/rubixdev/enchantedshulkers/mixin/PlayerInventoryMixin.java +++ b/src/main/java/de/rubixdev/enchantedshulkers/mixin/PlayerInventoryMixin.java @@ -1,6 +1,7 @@ package de.rubixdev.enchantedshulkers.mixin; import de.rubixdev.enchantedshulkers.enchantment.SiphonEnchantment; +import de.rubixdev.enchantedshulkers.enchantment.VacuumEnchantment; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.item.ItemStack; @@ -23,6 +24,8 @@ public void insertStack(ItemStack stack, CallbackInfoReturnable cir) { if (!(player instanceof ServerPlayerEntity serverPlayer)) return; if (SiphonEnchantment.onItemPickup(serverPlayer, stack) && stack.isEmpty()) { cir.setReturnValue(true); + } else if (VacuumEnchantment.onItemPickup(serverPlayer, stack) && stack.isEmpty()) { + cir.setReturnValue(true); } } } diff --git a/src/main/resources/assets/enchantedshulkers/lang/de_de.yml b/src/main/resources/assets/enchantedshulkers/lang/de_de.yml index 61c53f4..7703def 100644 --- a/src/main/resources/assets/enchantedshulkers/lang/de_de.yml +++ b/src/main/resources/assets/enchantedshulkers/lang/de_de.yml @@ -5,6 +5,9 @@ enchantment.enchantedshulkers: refill: Nachfüllen refill.desc: Gehaltene Gegenstände werden nach Benutzung automatisch nachgefüllt. + vacuum: Vakuum + vacuum.desc: Aufgesammelte Gegenstände werden gelagert wenn noch Platz ist. + commands.enchantedshulkers: all_options_title: 'Alle EnchantedShulkers Einstellungen:' current_value: 'Aktueller Wert: ' @@ -18,8 +21,11 @@ enchantedshulkers.options: coloredNames.desc: Färbe die Namen von platzierten verzauberten Kisten aqua. Diese option ist global für alle Spieler. creativeRefill.desc: Aktiviere die Nachfüllen Verzauberung für Spieler im Kreativmodus. creativeSiphon.desc: Aktiviere die Saugen Verzauberung für Spieler im Kreativmodus. + creativeVacuum.desc: Aktiviere die Vakuum Verzauberung für Spieler im Kreativmodus. enchantableEnderChest.desc: Endertruhen können auch verzaubert werden. - generateBooks.desc: Macht die Verzauberungen verfügbar im Überlebensmodus indem verzauberte Bücher mit diesen generieren können. + generateSiphon.desc: Macht die Saugen Verzauberung im Überlebensmodus verfügbar indem verzauberte Bücher mit ihr generieren können. + generateVacuum.desc: Macht die Vakuum Verzauberung im Überlebensmodus verfügbar indem verzauberte Bücher mit ihr generieren können. + generateRefill.desc: Macht die Nachfüllen Verzauberung im Überlebensmodus verfügbar indem verzauberte Bücher mit ihr generieren können. nestedContainers.desc: Suche rekursiv in Kisten bis zu 256 Stufen tief (z.B. suche durch Schulker-Kisten die sich in der Endertruhe befinden). refillNonStackables.desc: Erlaube das Nachfüllen von nicht stapelbaren Gegenständen wie z.B. Totems der Unsterblichkeit. refillOffhand.desc: Erlaube das Nachfüllen von Stapeln in der Zweithand. diff --git a/src/main/resources/assets/enchantedshulkers/lang/en_us.yml b/src/main/resources/assets/enchantedshulkers/lang/en_us.yml index 4793d4b..5d4e75e 100644 --- a/src/main/resources/assets/enchantedshulkers/lang/en_us.yml +++ b/src/main/resources/assets/enchantedshulkers/lang/en_us.yml @@ -5,6 +5,9 @@ enchantment.enchantedshulkers: refill: Refill refill.desc: Refills your held item from its inventory after use. + vacuum: Vacuum + vacuum.desc: Picked up items go in the storage if they fit anywhere. + commands.enchantedshulkers: all_options_title: 'All EnchantedShulkers options:' current_value: 'Current value: ' @@ -18,8 +21,11 @@ enchantedshulkers.options: coloredNames.desc: Show the names of placed enchanted containers in aqua color. This applies to all players. creativeRefill.desc: Enable the Refill enchantment for creative players. creativeSiphon.desc: Enable the Siphon enchantment for creative players. + creativeVacuum.desc: Enable the Vacuum enchantment for creative players. enchantableEnderChest.desc: Allows Ender Chests to also be enchanted. - generateBooks.desc: Make the enchantments obtainable in survival by allowing enchanted books to generate with them. + generateSiphon.desc: Make the Siphon enchantment obtainable in survival by allowing enchanted books to generate with it. + generateVacuum.desc: Make the Vacuum enchantment obtainable in survival by allowing enchanted books to generate with it. + generateRefill.desc: Make the Refill enchantment obtainable in survival by allowing enchanted books to generate with it. nestedContainers.desc: Search containers recursively up to 256 levels deep (e.g, search through Shulker Boxes in an Ender Chest). refillNonStackables.desc: Allow refilling non-stackable items like Totems of Undying. refillOffhand.desc: Allow refilling stacks in the offhand. diff --git a/src/main/resources/assets/enchantedshulkers/lang/zh_cn.yml b/src/main/resources/assets/enchantedshulkers/lang/zh_cn.yml index 9e55dc1..40fc7d6 100644 --- a/src/main/resources/assets/enchantedshulkers/lang/zh_cn.yml +++ b/src/main/resources/assets/enchantedshulkers/lang/zh_cn.yml @@ -5,6 +5,9 @@ enchantment.enchantedshulkers: refill: 补充 refill.desc: 手上的物品用完时,背包中的潜影盒内如果有相同的物品,就将之自动补充到手里 + # vacuum: Vacuum + # vacuum.desc: Picked up items go in the storage if they fit anywhere. + commands.enchantedshulkers: # all_options_title: 'All EnchantedShulkers options:' # current_value: 'Current value: ' @@ -18,8 +21,11 @@ enchantedshulkers.options: # coloredNames.desc: Show the names of placed enchanted containers in aqua color. This applies to all players. # creativeRefill.desc: Enable the Refill enchantment for creative players. # creativeSiphon.desc: Enable the Siphon enchantment for creative players. + # creativeVacuum.desc: Enable the Vacuum enchantment for creative players. # enchantableEnderChest.desc: Allows Ender Chests to also be enchanted. - # generateBooks.desc: Make the enchantments obtainable in survival by allowing enchanted books to generate with them. + # generateSiphon.desc: Make the Siphon enchantment obtainable in survival by allowing enchanted books to generate with it. + # generateVacuum.desc: Make the Vacuum enchantment obtainable in survival by allowing enchanted books to generate with it. + # generateRefill.desc: Make the Refill enchantment obtainable in survival by allowing enchanted books to generate with it. # nestedContainers.desc: Search containers recursively up to 256 levels deep (e.g, search through Shulker Boxes in an Ender Chest). # refillNonStackables.desc: Allow refilling non-stackable items like Totems of Undying. # refillOffhand.desc: Allow refilling stacks in the offhand.