Support for mod containers.

This commit is contained in:
IzzelAliz 2020-07-06 19:57:03 +08:00
parent 2e6ad0cfb0
commit 8b4a000bb9
8 changed files with 108 additions and 1 deletions

View File

@ -66,6 +66,7 @@ dependencies {
remapSpigotJar {
includes.add('net/minecraft/block/ChestBlock$DoubleInventory')
includes.add('net/minecraft/tileentity/LecternTileEntity$LecternInventory')
}
generateArclightMeta {

View File

@ -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<InventoryType> cir) {
if (inventory.getClass().getDeclaringClass() == LecternTileEntity.class) {
cir.setReturnValue(InventoryType.LECTERN);
}
}
}

View File

@ -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<ItemStack> 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"))

View File

@ -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<IInventory> 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();

View File

@ -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);
}

View File

@ -15,6 +15,7 @@
"CraftConsoleCommandSenderMixin",
"CraftEntityMixin",
"CraftEventFactoryMixin",
"CraftInventoryMixin",
"CraftItemFactoryMixin",
"CraftMagicNumbersMixin",
"CraftServerMixin",

View File

@ -115,6 +115,7 @@ jar {
remapSpigotJar {
includes.add('net/minecraft/block/ChestBlock$DoubleInventory')
includes.add('net/minecraft/tileentity/LecternTileEntity$LecternInventory')
}
mixin {

View File

@ -115,6 +115,7 @@ jar {
remapSpigotJar {
includes.add('net/minecraft/block/ChestBlock$DoubleInventory')
includes.add('net/minecraft/tileentity/LecternTileEntity$LecternInventory')
}
mixin {