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 { remapSpigotJar {
includes.add('net/minecraft/block/ChestBlock$DoubleInventory') includes.add('net/minecraft/block/ChestBlock$DoubleInventory')
includes.add('net/minecraft/tileentity/LecternTileEntity$LecternInventory')
} }
generateArclightMeta { 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.inventory.container.ContainerBridge;
import io.izzel.arclight.common.bridge.util.FoodStatsBridge; import io.izzel.arclight.common.bridge.util.FoodStatsBridge;
import io.izzel.arclight.common.bridge.world.WorldBridge; 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 io.izzel.arclight.common.mod.util.ChestBlockDoubleInventoryHacks;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
@ -397,9 +398,11 @@ public abstract class ServerPlayerEntityMixin extends PlayerEntityMixin implemen
@Inject(method = "sendAllContents", at = @At("RETURN")) @Inject(method = "sendAllContents", at = @At("RETURN"))
private void arclight$sendExtra(Container container, NonNullList<ItemStack> itemsList, CallbackInfo ci) { 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())) { 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())); this.connection.sendPacket(new SSetSlotPacket(container.windowId, 0, container.getSlot(0).getStack()));
} }
ArclightCaptures.resetContainerOwner();
} }
@Inject(method = "closeScreen", at = @At("HEAD")) @Inject(method = "closeScreen", at = @At("HEAD"))

View File

@ -1,13 +1,18 @@
package io.izzel.arclight.common.mixin.core.inventory.container; package io.izzel.arclight.common.mixin.core.inventory.container;
import com.google.common.base.Preconditions; 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.IInventoryBridge;
import io.izzel.arclight.common.bridge.inventory.container.ContainerBridge; import io.izzel.arclight.common.bridge.inventory.container.ContainerBridge;
import io.izzel.arclight.common.bridge.inventory.container.SlotBridge; 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.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory; import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity; 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.ClickType;
import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Container;
import net.minecraft.inventory.container.Slot; import net.minecraft.inventory.container.Slot;
@ -18,10 +23,13 @@ import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.craftbukkit.v.entity.CraftHumanEntity; import org.bukkit.craftbukkit.v.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v.inventory.CraftInventory; 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.craftbukkit.v.inventory.CraftItemStack;
import org.bukkit.event.Event; import org.bukkit.event.Event;
import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.InventoryView;
import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin; 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 org.spongepowered.asm.mixin.injection.Redirect;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -54,8 +63,59 @@ public abstract class ContainerMixin implements ContainerBridge {
// @formatter:on // @formatter:on
public boolean checkReachable = true; 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) { public void transferTo(Container other, CraftHumanEntity player) {
InventoryView source = this.getBukkitView(); 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 io.izzel.arclight.common.mod.ArclightConstants;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.entity.item.ItemEntity; import net.minecraft.entity.item.ItemEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.Container; import net.minecraft.inventory.container.Container;
import net.minecraft.util.Direction; import net.minecraft.util.Direction;
import net.minecraft.util.Hand; 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) { private static void recapture(String type) {
throw new IllegalStateException("Recapturing " + type); throw new IllegalStateException("Recapturing " + type);
} }

View File

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

View File

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

View File

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