diff options
author | NotNite <hi@notnite.com> | 2023-06-20 15:09:55 -0400 |
---|---|---|
committer | NotNite <hi@notnite.com> | 2023-06-20 15:09:55 -0400 |
commit | 20692e21107a35f5f45651f655a6a564fc570007 (patch) | |
tree | 3177242a0dffb4361dcf7ab4592fed12c4ccfb77 /src | |
download | gloppers-20692e21107a35f5f45651f655a6a564fc570007.tar.gz gloppers-20692e21107a35f5f45651f655a6a564fc570007.tar.bz2 gloppers-20692e21107a35f5f45651f655a6a564fc570007.zip |
Initial commit
Diffstat (limited to 'src')
-rw-r--r-- | src/main/java/com/notnite/gloppers/mixin/HopperBlockEntityMixin.java | 65 | ||||
-rw-r--r-- | src/main/kotlin/com/notnite/gloppers/Gloppers.kt | 41 | ||||
-rw-r--r-- | src/main/resources/assets/gloppers/icon.png | bin | 0 -> 11413 bytes | |||
-rw-r--r-- | src/main/resources/fabric.mod.json | 37 | ||||
-rw-r--r-- | src/main/resources/gloppers.mixins.json | 11 |
5 files changed, 154 insertions, 0 deletions
diff --git a/src/main/java/com/notnite/gloppers/mixin/HopperBlockEntityMixin.java b/src/main/java/com/notnite/gloppers/mixin/HopperBlockEntityMixin.java new file mode 100644 index 0000000..78468ac --- /dev/null +++ b/src/main/java/com/notnite/gloppers/mixin/HopperBlockEntityMixin.java @@ -0,0 +1,65 @@ +package com.notnite.gloppers.mixin; + +import com.notnite.gloppers.Gloppers; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.entity.Hopper; +import net.minecraft.block.entity.HopperBlockEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.Direction; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Environment(EnvType.SERVER) +@Mixin(HopperBlockEntity.class) +public class HopperBlockEntityMixin { + private static int dirtySlotState = 0; + + // We can't decrement the item stack before it gets passed to transfer, because we may not be allowed to transfer, + // eating an item. We know removeStack will get called immediately before transfer, so while it's messy, we can use + // a static variable to keep track of what slot we're removing from. + @Redirect( + method = "insert", + at = @At(value = "INVOKE", target = "Lnet/minecraft/inventory/Inventory;removeStack(II)Lnet/minecraft/item/ItemStack;") + ) + private static ItemStack insert$gloppersRemoveStack(Inventory instance, int slot, int amount) { + dirtySlotState = slot; + return instance.getStack(slot); + } + + // This works by mixing into the call of HopperBlockEntity::transfer and returning a stubbed item stack if it's not + // allowed to transfer. I wanted to instead insert a continue statement into the for loop, but I couldn't figure out + // a good way to do that. + @Redirect( + method = "insert", + at = @At(value = "INVOKE", target = "Lnet/minecraft/block/entity/HopperBlockEntity;transfer(Lnet/minecraft/inventory/Inventory;Lnet/minecraft/inventory/Inventory;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/math/Direction;)Lnet/minecraft/item/ItemStack;") + ) + private static ItemStack insert$gloppersTransfer( + Inventory from, Inventory to, ItemStack stack, Direction side + ) { + if (!Gloppers.INSTANCE.canTransfer(to, stack)) { + // The return value of this is only used to check if it's empty, and if so, returns that it succeeded. + // We can just return the item stack we were given, as we didn't remove from it. + return stack; + } + + // Make sure to remove the item here, because we didn't in the actual call. + return HopperBlockEntity.transfer(from, to, from.removeStack(dirtySlotState, 1), side); + } + + // This handles the case where a hopper extracts from a hopper above it (such as two anvils facing forward, stacked + // on top of one another). + @Inject( + method = "extract(Lnet/minecraft/block/entity/Hopper;Lnet/minecraft/inventory/Inventory;ILnet/minecraft/util/math/Direction;)Z", + at = @At("HEAD"), + cancellable = true + ) + private static void extract(Hopper hopper, Inventory inventory, int slot, Direction side, CallbackInfoReturnable<Boolean> cir) { + var item = inventory.getStack(slot); + if (!Gloppers.INSTANCE.canTransfer(hopper, item)) cir.setReturnValue(false); + } +} diff --git a/src/main/kotlin/com/notnite/gloppers/Gloppers.kt b/src/main/kotlin/com/notnite/gloppers/Gloppers.kt new file mode 100644 index 0000000..bdea779 --- /dev/null +++ b/src/main/kotlin/com/notnite/gloppers/Gloppers.kt @@ -0,0 +1,41 @@ +package com.notnite.gloppers + +import net.fabricmc.api.DedicatedServerModInitializer +import net.minecraft.block.entity.HopperBlockEntity +import net.minecraft.inventory.Inventory +import net.minecraft.item.ItemStack + +object Gloppers : DedicatedServerModInitializer { + override fun onInitializeServer() {} + + private fun matchesGlob(glob: String, str: String): Boolean { + val regex = glob + .replace(".", "\\.") + .replace("*", ".*") + .replace("?", ".") + return str.matches(regex.toRegex()) + } + + fun canTransfer(to: Inventory, stack: ItemStack): Boolean { + if (to is HopperBlockEntity) { + val hopperName = to.name.copyContentOnly().string + val itemName = stack.registryEntry.key.get().value.path + + if (hopperName.startsWith("!")) { + val globs = hopperName.substring(1).split(",") + for (glob in globs) { + if (matchesGlob(glob, itemName)) { + // Glob matched, transfer + return true + } + } + + // No globs matched, so don't transfer + return false + } + } + + // Doesn't have a glob, so transfer + return true + } +} diff --git a/src/main/resources/assets/gloppers/icon.png b/src/main/resources/assets/gloppers/icon.png Binary files differnew file mode 100644 index 0000000..25b7fb6 --- /dev/null +++ b/src/main/resources/assets/gloppers/icon.png diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..7599de5 --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,37 @@ +{ + "schemaVersion": 1, + "id": "gloppers", + "version": "${version}", + "name": "Gloppers!", + "description": "Filter your hoppers by renaming them with glob patterns.", + "authors": [ + "NotNite" + ], + "contact": { + "sources": "https://github.com/NotNite/gloppers" + }, + "license": "MIT", + "icon": "assets/gloppers/icon.png", + "environment": "server", + "entrypoints": { + "server": [ + { + "value": "com.notnite.gloppers.Gloppers", + "adapter": "kotlin" + } + ] + }, + "mixins": [ + { + "environment": "server", + "config": "gloppers.mixins.json" + } + ], + "depends": { + "fabricloader": ">=0.14.19", + "minecraft": "~1.20", + "java": ">=17", + "fabric-api": "*", + "fabric-language-kotlin": ">=1.8.22" + } +} diff --git a/src/main/resources/gloppers.mixins.json b/src/main/resources/gloppers.mixins.json new file mode 100644 index 0000000..6ddce8d --- /dev/null +++ b/src/main/resources/gloppers.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "com.notnite.gloppers.mixin", + "compatibilityLevel": "JAVA_17", + "server": [ + "HopperBlockEntityMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} |