From 8b4a000bb9857fe88bde95e6b2bf0a9c276f6149 Mon Sep 17 00:00:00 2001 From: IzzelAliz Date: Mon, 6 Jul 2020 19:57:03 +0800 Subject: [PATCH] Support for mod containers. --- arclight-common/build.gradle | 1 + .../mixin/bukkit/CraftInventoryMixin.java | 25 ++++++++ .../player/ServerPlayerEntityMixin.java | 3 + .../inventory/container/ContainerMixin.java | 62 ++++++++++++++++++- .../common/mod/util/ArclightCaptures.java | 15 +++++ .../resources/mixins.arclight.bukkit.json | 1 + arclight-forge-1.14/build.gradle | 1 + arclight-forge-1.15/build.gradle | 1 + 8 files changed, 108 insertions(+), 1 deletion(-) create mode 100644 arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftInventoryMixin.java diff --git a/arclight-common/build.gradle b/arclight-common/build.gradle index cb9a4815..865a23f9 100644 --- a/arclight-common/build.gradle +++ b/arclight-common/build.gradle @@ -66,6 +66,7 @@ dependencies { remapSpigotJar { includes.add('net/minecraft/block/ChestBlock$DoubleInventory') + includes.add('net/minecraft/tileentity/LecternTileEntity$LecternInventory') } generateArclightMeta { diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftInventoryMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftInventoryMixin.java new file mode 100644 index 00000000..a185f30d --- /dev/null +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftInventoryMixin.java @@ -0,0 +1,25 @@ +package io.izzel.arclight.common.mixin.bukkit; + +import net.minecraft.inventory.IInventory; +import net.minecraft.tileentity.LecternTileEntity; +import org.bukkit.craftbukkit.v.inventory.CraftInventory; +import org.bukkit.event.inventory.InventoryType; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(value = CraftInventory.class, remap = false) +public class CraftInventoryMixin { + + @Shadow @Final protected IInventory inventory; + + @Inject(method = "getType", cancellable = true, at = @At("HEAD")) + private void arclight$lecternType(CallbackInfoReturnable cir) { + if (inventory.getClass().getDeclaringClass() == LecternTileEntity.class) { + cir.setReturnValue(InventoryType.LECTERN); + } + } +} diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/entity/player/ServerPlayerEntityMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/entity/player/ServerPlayerEntityMixin.java index 6d6fd039..a00d5531 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/entity/player/ServerPlayerEntityMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/entity/player/ServerPlayerEntityMixin.java @@ -7,6 +7,7 @@ import io.izzel.arclight.common.bridge.entity.player.ServerPlayerEntityBridge; import io.izzel.arclight.common.bridge.inventory.container.ContainerBridge; import io.izzel.arclight.common.bridge.util.FoodStatsBridge; import io.izzel.arclight.common.bridge.world.WorldBridge; +import io.izzel.arclight.common.mod.util.ArclightCaptures; import io.izzel.arclight.common.mod.util.ChestBlockDoubleInventoryHacks; import net.minecraft.entity.Entity; import net.minecraft.entity.LivingEntity; @@ -397,9 +398,11 @@ public abstract class ServerPlayerEntityMixin extends PlayerEntityMixin implemen @Inject(method = "sendAllContents", at = @At("RETURN")) private void arclight$sendExtra(Container container, NonNullList itemsList, CallbackInfo ci) { + ArclightCaptures.captureContainerOwner((ServerPlayerEntity) (Object) this); if (EnumSet.of(InventoryType.CRAFTING, InventoryType.WORKBENCH).contains(((ContainerBridge) container).bridge$getBukkitView().getType())) { this.connection.sendPacket(new SSetSlotPacket(container.windowId, 0, container.getSlot(0).getStack())); } + ArclightCaptures.resetContainerOwner(); } @Inject(method = "closeScreen", at = @At("HEAD")) diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/inventory/container/ContainerMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/inventory/container/ContainerMixin.java index beae3037..d47dfa9b 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/inventory/container/ContainerMixin.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/core/inventory/container/ContainerMixin.java @@ -1,13 +1,18 @@ package io.izzel.arclight.common.mixin.core.inventory.container; import com.google.common.base.Preconditions; +import io.izzel.arclight.common.bridge.entity.player.PlayerEntityBridge; import io.izzel.arclight.common.bridge.inventory.IInventoryBridge; import io.izzel.arclight.common.bridge.inventory.container.ContainerBridge; import io.izzel.arclight.common.bridge.inventory.container.SlotBridge; +import io.izzel.arclight.common.mod.ArclightMod; +import io.izzel.arclight.common.mod.util.ArclightCaptures; import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.CraftResultInventory; +import net.minecraft.inventory.IInventory; import net.minecraft.inventory.container.ClickType; import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Slot; @@ -18,10 +23,13 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.craftbukkit.v.entity.CraftHumanEntity; import org.bukkit.craftbukkit.v.inventory.CraftInventory; +import org.bukkit.craftbukkit.v.inventory.CraftInventoryCustom; +import org.bukkit.craftbukkit.v.inventory.CraftInventoryView; import org.bukkit.craftbukkit.v.inventory.CraftItemStack; import org.bukkit.event.Event; import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryView; import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; @@ -31,6 +39,7 @@ import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Redirect; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -54,8 +63,59 @@ public abstract class ContainerMixin implements ContainerBridge { // @formatter:on public boolean checkReachable = true; + private InventoryView bukkitView; - public abstract InventoryView getBukkitView(); + // todo check this + public InventoryView getBukkitView() { + if (bukkitView == null) { + PlayerEntity candidate = null; + Set set = new HashSet<>(); + for (Slot slot : this.inventorySlots) { + if (slot.inventory != null) { + if (slot.inventory instanceof PlayerInventory) { + if (candidate != null && ((PlayerInventory) slot.inventory).player != candidate) { + ArclightMod.LOGGER.warn("Duplicate PlayerInventory inside {}, previous {}, new {}", this, candidate, slot.inventory); + } + candidate = ((PlayerInventory) slot.inventory).player; + } else { + set.add(slot.inventory); + } + } + } + if (candidate == null) { + if (ArclightCaptures.getContainerOwner() != null) { + candidate = ArclightCaptures.getContainerOwner(); + } else { + throw new RuntimeException("candidate cannot be null"); + } + } + CraftResultInventory resultCandidate = null; + IInventory mainCandidate = null; + for (IInventory inventory : set) { + if (inventory instanceof CraftResultInventory) { + resultCandidate = (CraftResultInventory) inventory; + } else { + mainCandidate = inventory; + } + } + Inventory inv; + if (mainCandidate == null && resultCandidate != null) { + mainCandidate = resultCandidate; + resultCandidate = null; + } + if (mainCandidate != null) { + if (resultCandidate != null) { + inv = new org.bukkit.craftbukkit.v.inventory.CraftResultInventory(mainCandidate, resultCandidate); + } else { + inv = new CraftInventory(mainCandidate); + } + } else { // container has no slots + inv = new CraftInventoryCustom(((PlayerEntityBridge) candidate).bridge$getBukkitEntity(), 0); + } + bukkitView = new CraftInventoryView(((PlayerEntityBridge) candidate).bridge$getBukkitEntity(), inv, (Container) (Object) this); + } + return bukkitView; + } public void transferTo(Container other, CraftHumanEntity player) { InventoryView source = this.getBukkitView(); diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/ArclightCaptures.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/ArclightCaptures.java index 9a50c8f0..0f0211c3 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/ArclightCaptures.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/util/ArclightCaptures.java @@ -3,6 +3,7 @@ package io.izzel.arclight.common.mod.util; import io.izzel.arclight.common.mod.ArclightConstants; import net.minecraft.entity.Entity; import net.minecraft.entity.item.ItemEntity; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.inventory.container.Container; import net.minecraft.util.Direction; import net.minecraft.util.Hand; @@ -180,6 +181,20 @@ public class ArclightCaptures { } } + private static transient PlayerEntity containerOwner; + + public static void captureContainerOwner(PlayerEntity entity) { + containerOwner = entity; + } + + public static PlayerEntity getContainerOwner() { + return containerOwner; + } + + public static void resetContainerOwner() { + containerOwner = null; + } + private static void recapture(String type) { throw new IllegalStateException("Recapturing " + type); } diff --git a/arclight-common/src/main/resources/mixins.arclight.bukkit.json b/arclight-common/src/main/resources/mixins.arclight.bukkit.json index e1eed299..d3852ee8 100644 --- a/arclight-common/src/main/resources/mixins.arclight.bukkit.json +++ b/arclight-common/src/main/resources/mixins.arclight.bukkit.json @@ -15,6 +15,7 @@ "CraftConsoleCommandSenderMixin", "CraftEntityMixin", "CraftEventFactoryMixin", + "CraftInventoryMixin", "CraftItemFactoryMixin", "CraftMagicNumbersMixin", "CraftServerMixin", diff --git a/arclight-forge-1.14/build.gradle b/arclight-forge-1.14/build.gradle index f1f34e26..614347aa 100644 --- a/arclight-forge-1.14/build.gradle +++ b/arclight-forge-1.14/build.gradle @@ -115,6 +115,7 @@ jar { remapSpigotJar { includes.add('net/minecraft/block/ChestBlock$DoubleInventory') + includes.add('net/minecraft/tileentity/LecternTileEntity$LecternInventory') } mixin { diff --git a/arclight-forge-1.15/build.gradle b/arclight-forge-1.15/build.gradle index 57ffc5c4..7432aebb 100644 --- a/arclight-forge-1.15/build.gradle +++ b/arclight-forge-1.15/build.gradle @@ -115,6 +115,7 @@ jar { remapSpigotJar { includes.add('net/minecraft/block/ChestBlock$DoubleInventory') + includes.add('net/minecraft/tileentity/LecternTileEntity$LecternInventory') } mixin {