aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNotNite <hi@notnite.com>2023-06-20 15:09:55 -0400
committerNotNite <hi@notnite.com>2023-06-20 15:09:55 -0400
commit20692e21107a35f5f45651f655a6a564fc570007 (patch)
tree3177242a0dffb4361dcf7ab4592fed12c4ccfb77 /src
downloadgloppers-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.java65
-rw-r--r--src/main/kotlin/com/notnite/gloppers/Gloppers.kt41
-rw-r--r--src/main/resources/assets/gloppers/icon.pngbin0 -> 11413 bytes
-rw-r--r--src/main/resources/fabric.mod.json37
-rw-r--r--src/main/resources/gloppers.mixins.json11
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
new file mode 100644
index 0000000..25b7fb6
--- /dev/null
+++ b/src/main/resources/assets/gloppers/icon.png
Binary files differ
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
+ }
+}