Add compat for /dank/null
This commit is contained in:
@@ -127,6 +127,10 @@ dependencies {
|
|||||||
compileOnly "curse.maven:jei-238222:7391682"
|
compileOnly "curse.maven:jei-238222:7391682"
|
||||||
localRuntime "curse.maven:jade-324717:6155158"
|
localRuntime "curse.maven:jade-324717:6155158"
|
||||||
localRuntime "curse.maven:jei-238222:7391682"
|
localRuntime "curse.maven:jei-238222:7391682"
|
||||||
|
localRuntime "curse.maven:travelers-backpack-321117:7485008"
|
||||||
|
localRuntime "curse.maven:sophisticated-core-618298:7635107"
|
||||||
|
localRuntime "curse.maven:sophisticated-backpacks-422301:7645643"
|
||||||
|
localRuntime "curse.maven:dank-storage-335673:7539725"
|
||||||
}
|
}
|
||||||
|
|
||||||
// This block of code expands all declared replace properties in the specified resource targets.
|
// This block of code expands all declared replace properties in the specified resource targets.
|
||||||
|
|||||||
@@ -16,8 +16,9 @@ public final class BagAccess {
|
|||||||
|
|
||||||
for (int slot = 0; slot < inventory.getContainerSize(); slot++) {
|
for (int slot = 0; slot < inventory.getContainerSize(); slot++) {
|
||||||
ItemStack stack = inventory.getItem(slot);
|
ItemStack stack = inventory.getItem(slot);
|
||||||
if (stack.getItem() instanceof InventoryBag inventoryBag) {
|
BagCompat.BagHandler handler = BagCompat.findHandler(stack);
|
||||||
bags.add(new BagEntry(slot, stack.copy(), inventoryBag));
|
if (handler != null) {
|
||||||
|
bags.add(new BagEntry(slot, stack.copy(), handler));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
279
src/main/java/com/trunksbomb/bagtabs/bag/BagCompat.java
Normal file
279
src/main/java/com/trunksbomb/bagtabs/bag/BagCompat.java
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
package com.trunksbomb.bagtabs.bag;
|
||||||
|
|
||||||
|
import com.trunksbomb.bagtabs.menu.BagMenu;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.List;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.MenuProvider;
|
||||||
|
import net.minecraft.world.entity.player.Inventory;
|
||||||
|
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
|
public final class BagCompat {
|
||||||
|
private static final List<BagHandler> HANDLERS = List.of(
|
||||||
|
new NativeBagHandler(),
|
||||||
|
new DankStorageHandler(),
|
||||||
|
new TravelersBackpackHandler(),
|
||||||
|
new SophisticatedBackpacksHandler()
|
||||||
|
);
|
||||||
|
|
||||||
|
private BagCompat() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BagHandler findHandler(ItemStack stack) {
|
||||||
|
if (stack.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BagHandler handler : HANDLERS) {
|
||||||
|
if (handler.supports(stack)) {
|
||||||
|
return handler;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean supportsMenu(AbstractContainerMenu menu) {
|
||||||
|
return getActiveBagSlot(menu) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getActiveBagSlot(AbstractContainerMenu menu) {
|
||||||
|
if (menu instanceof BagMenu bagMenu) {
|
||||||
|
return bagMenu.getBagSlot();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (BagHandler handler : HANDLERS) {
|
||||||
|
int slot = handler.getActiveBagSlot(menu);
|
||||||
|
if (slot >= 0) {
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface BagHandler {
|
||||||
|
boolean supports(ItemStack stack);
|
||||||
|
|
||||||
|
void open(ServerPlayer player, int slot, ItemStack stack);
|
||||||
|
|
||||||
|
default int getActiveBagSlot(AbstractContainerMenu menu) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class NativeBagHandler implements BagHandler {
|
||||||
|
@Override
|
||||||
|
public boolean supports(ItemStack stack) {
|
||||||
|
return stack.getItem() instanceof InventoryBag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open(ServerPlayer player, int slot, ItemStack stack) {
|
||||||
|
if (stack.getItem() instanceof InventoryBag inventoryBag) {
|
||||||
|
inventoryBag.openFromInventory(player, slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class TravelersBackpackHandler implements BagHandler {
|
||||||
|
private static final String ITEM_CLASS = "com.tiviacz.travelersbackpack.items.TravelersBackpackItem";
|
||||||
|
private static final String MENU_CLASS = "com.tiviacz.travelersbackpack.inventory.menu.AbstractBackpackMenu";
|
||||||
|
private static final String WRAPPER_CLASS = "com.tiviacz.travelersbackpack.inventory.BackpackWrapper";
|
||||||
|
private static final String CONTAINER_CLASS = "com.tiviacz.travelersbackpack.inventory.BackpackContainer";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(ItemStack stack) {
|
||||||
|
return isInstance(ITEM_CLASS, stack.getItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open(ServerPlayer player, int slot, ItemStack stack) {
|
||||||
|
invokeStatic(
|
||||||
|
CONTAINER_CLASS,
|
||||||
|
"openBackpack",
|
||||||
|
new Class<?>[] {ServerPlayer.class, ItemStack.class, int.class, int.class},
|
||||||
|
player,
|
||||||
|
stack,
|
||||||
|
1,
|
||||||
|
slot
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getActiveBagSlot(AbstractContainerMenu menu) {
|
||||||
|
if (!isInstance(MENU_CLASS, menu)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object wrapper = invoke(menu, "getWrapper");
|
||||||
|
if (wrapper == null || !isInstance(WRAPPER_CLASS, wrapper)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object slot = invoke(wrapper, "getBackpackSlotIndex");
|
||||||
|
return slot instanceof Integer integer ? integer : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class DankStorageHandler implements BagHandler {
|
||||||
|
private static final String ITEM_CLASS = "tfar.dankstorage.item.DankItem";
|
||||||
|
private static final String MENU_CLASS = "tfar.dankstorage.menu.DankMenu";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(ItemStack stack) {
|
||||||
|
return isInstance(ITEM_CLASS, stack.getItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open(ServerPlayer player, int slot, ItemStack stack) {
|
||||||
|
try {
|
||||||
|
Method createProvider = stack.getItem().getClass().getMethod("createProvider", ItemStack.class);
|
||||||
|
Object provider = createProvider.invoke(stack.getItem(), stack);
|
||||||
|
if (provider instanceof MenuProvider menuProvider) {
|
||||||
|
player.openMenu(menuProvider);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalStateException("Dank Storage did not return a MenuProvider");
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException exception) {
|
||||||
|
throw new RuntimeException("Failed to open Dank Storage via compatibility bridge", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getActiveBagSlot(AbstractContainerMenu menu) {
|
||||||
|
if (!isInstance(MENU_CLASS, menu)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object bag = invoke(menu, "getBag");
|
||||||
|
if (!(bag instanceof ItemStack bagStack) || bagStack.isEmpty()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return findMatchingPlayerSlot(menu, bagStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final class SophisticatedBackpacksHandler implements BagHandler {
|
||||||
|
private static final String ITEM_CLASS = "net.p3pp3rf1y.sophisticatedbackpacks.backpack.BackpackItem";
|
||||||
|
private static final String MENU_CLASS = "net.p3pp3rf1y.sophisticatedbackpacks.common.gui.BackpackContainer";
|
||||||
|
private static final String CONTEXT_CLASS = "net.p3pp3rf1y.sophisticatedbackpacks.common.gui.BackpackContext";
|
||||||
|
private static final String PAYLOAD_CLASS = "net.p3pp3rf1y.sophisticatedbackpacks.network.BackpackOpenPayload";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supports(ItemStack stack) {
|
||||||
|
return isInstance(ITEM_CLASS, stack.getItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void open(ServerPlayer player, int slot, ItemStack stack) {
|
||||||
|
try {
|
||||||
|
Class<?> payloadClass = Class.forName(PAYLOAD_CLASS);
|
||||||
|
Method handlePayload = payloadClass.getMethod(
|
||||||
|
"handlePayload",
|
||||||
|
payloadClass,
|
||||||
|
Class.forName("net.neoforged.neoforge.network.handling.IPayloadContext")
|
||||||
|
);
|
||||||
|
Object payload = payloadClass.getConstructor(int.class).newInstance(slot);
|
||||||
|
handlePayload.invoke(null, payload, new ServerPayloadContext(player));
|
||||||
|
} catch (ReflectiveOperationException exception) {
|
||||||
|
throw new RuntimeException("Failed to open Sophisticated Backpack via compatibility bridge", exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getActiveBagSlot(AbstractContainerMenu menu) {
|
||||||
|
if (!isInstance(MENU_CLASS, menu)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object context = invoke(menu, "getBackpackContext");
|
||||||
|
if (context == null || !isInstance(CONTEXT_CLASS, context)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object slot = invoke(context, "getBackpackSlotIndex");
|
||||||
|
return slot instanceof Integer integer ? integer : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int findMatchingPlayerSlot(AbstractContainerMenu menu, ItemStack bagStack) {
|
||||||
|
Inventory playerInventory = findPlayerInventory(menu);
|
||||||
|
if (playerInventory == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Slot slot : menu.slots) {
|
||||||
|
if (slot.container != playerInventory) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack slotStack = slot.getItem();
|
||||||
|
if (slotStack == bagStack) {
|
||||||
|
return slot.getContainerSlot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Slot slot : menu.slots) {
|
||||||
|
if (slot.container != playerInventory) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ItemStack slotStack = slot.getItem();
|
||||||
|
if (ItemStack.isSameItemSameComponents(slotStack, bagStack)) {
|
||||||
|
return slot.getContainerSlot();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Inventory findPlayerInventory(AbstractContainerMenu menu) {
|
||||||
|
for (Slot slot : menu.slots) {
|
||||||
|
if (slot.container instanceof Inventory inventory) {
|
||||||
|
return inventory;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field inventoryField = menu.getClass().getField("playerInventory");
|
||||||
|
Object inventory = inventoryField.get(menu);
|
||||||
|
return inventory instanceof Inventory playerInventory ? playerInventory : null;
|
||||||
|
} catch (IllegalAccessException | NoSuchFieldException exception) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean isInstance(String className, Object instance) {
|
||||||
|
try {
|
||||||
|
return instance != null && Class.forName(className).isInstance(instance);
|
||||||
|
} catch (ClassNotFoundException exception) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Object invoke(Object target, String methodName) {
|
||||||
|
try {
|
||||||
|
Method method = target.getClass().getMethod(methodName);
|
||||||
|
return method.invoke(target);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException exception) {
|
||||||
|
throw new RuntimeException("Failed to invoke " + methodName + " on " + target.getClass().getName(), exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void invokeStatic(String className, String methodName, Class<?>[] parameterTypes, Object... args) {
|
||||||
|
try {
|
||||||
|
Class<?> targetClass = Class.forName(className);
|
||||||
|
Method method = targetClass.getMethod(methodName, parameterTypes);
|
||||||
|
method.invoke(null, args);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException exception) {
|
||||||
|
throw new RuntimeException("Failed to invoke compatibility method " + className + "#" + methodName, exception);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,5 +2,5 @@ package com.trunksbomb.bagtabs.bag;
|
|||||||
|
|
||||||
import net.minecraft.world.item.ItemStack;
|
import net.minecraft.world.item.ItemStack;
|
||||||
|
|
||||||
public record BagEntry(int slot, ItemStack stack, InventoryBag bag) {
|
public record BagEntry(int slot, ItemStack stack, BagCompat.BagHandler handler) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
package com.trunksbomb.bagtabs.bag;
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
import net.minecraft.network.Connection;
|
||||||
|
import net.minecraft.network.chat.Component;
|
||||||
|
import net.minecraft.network.protocol.Packet;
|
||||||
|
import net.minecraft.network.protocol.PacketFlow;
|
||||||
|
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.network.ConfigurationTask;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.neoforged.neoforge.common.extensions.ICommonPacketListener;
|
||||||
|
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||||
|
|
||||||
|
public class ServerPayloadContext implements IPayloadContext {
|
||||||
|
private final ServerPlayer player;
|
||||||
|
|
||||||
|
public ServerPayloadContext(ServerPlayer player) {
|
||||||
|
this.player = player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ICommonPacketListener listener() {
|
||||||
|
return (ICommonPacketListener)this.player.connection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Player player() {
|
||||||
|
return this.player;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Void> enqueueWork(Runnable task) {
|
||||||
|
task.run();
|
||||||
|
return CompletableFuture.completedFuture(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> CompletableFuture<T> enqueueWork(Supplier<T> task) {
|
||||||
|
return CompletableFuture.completedFuture(task.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PacketFlow flow() {
|
||||||
|
return PacketFlow.SERVERBOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(CustomPacketPayload payload) {
|
||||||
|
throw new UnsupportedOperationException("Nested payload handling is not supported by this compatibility context");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void finishCurrentTask(ConfigurationTask.Type type) {
|
||||||
|
throw new UnsupportedOperationException("Configuration tasks are not supported by this compatibility context");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection connection() {
|
||||||
|
return this.player.connection.getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reply(CustomPacketPayload payload) {
|
||||||
|
this.player.connection.send(payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void disconnect(Component reason) {
|
||||||
|
this.player.connection.disconnect(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void handle(Packet<?> packet) {
|
||||||
|
throw new UnsupportedOperationException("Packet forwarding is not supported by this compatibility context");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ChannelHandlerContext channelHandlerContext() {
|
||||||
|
return this.player.connection.getConnection().channel().pipeline().lastContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,8 +2,10 @@ package com.trunksbomb.bagtabs.client;
|
|||||||
|
|
||||||
import com.trunksbomb.bagtabs.BagTabs;
|
import com.trunksbomb.bagtabs.BagTabs;
|
||||||
import com.trunksbomb.bagtabs.bag.BagAccess;
|
import com.trunksbomb.bagtabs.bag.BagAccess;
|
||||||
|
import com.trunksbomb.bagtabs.bag.BagCompat;
|
||||||
import com.trunksbomb.bagtabs.bag.BagEntry;
|
import com.trunksbomb.bagtabs.bag.BagEntry;
|
||||||
import com.trunksbomb.bagtabs.item.BagItem;
|
import com.trunksbomb.bagtabs.item.BagItem;
|
||||||
|
import com.trunksbomb.bagtabs.menu.BagMenu;
|
||||||
import com.trunksbomb.bagtabs.network.OpenBagPayload;
|
import com.trunksbomb.bagtabs.network.OpenBagPayload;
|
||||||
import com.mojang.blaze3d.systems.RenderSystem;
|
import com.mojang.blaze3d.systems.RenderSystem;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -11,12 +13,12 @@ import java.util.List;
|
|||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.gui.GuiGraphics;
|
import net.minecraft.client.gui.GuiGraphics;
|
||||||
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
|
||||||
import net.minecraft.client.gui.screens.inventory.InventoryScreen;
|
|
||||||
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
import net.minecraft.client.resources.sounds.SimpleSoundInstance;
|
||||||
import net.minecraft.resources.ResourceLocation;
|
import net.minecraft.resources.ResourceLocation;
|
||||||
import net.minecraft.sounds.SoundEvents;
|
import net.minecraft.sounds.SoundEvents;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
import net.minecraft.world.item.component.DyedItemColor;
|
import net.minecraft.world.item.component.DyedItemColor;
|
||||||
|
import net.minecraft.world.inventory.Slot;
|
||||||
import net.neoforged.neoforge.client.event.ScreenEvent;
|
import net.neoforged.neoforge.client.event.ScreenEvent;
|
||||||
import net.neoforged.neoforge.network.PacketDistributor;
|
import net.neoforged.neoforge.network.PacketDistributor;
|
||||||
|
|
||||||
@@ -27,13 +29,13 @@ public final class BagTabOverlay {
|
|||||||
private static final int TAB_HEIGHT = 22;
|
private static final int TAB_HEIGHT = 22;
|
||||||
private static final int TAB_GAP = 0;
|
private static final int TAB_GAP = 0;
|
||||||
private static final int TAB_Y_OFFSET = -3;
|
private static final int TAB_Y_OFFSET = -3;
|
||||||
private static final int TAB_X_OFFSET = 7;
|
private static final int TAB_X_OFFSET = -6;
|
||||||
|
|
||||||
private BagTabOverlay() {
|
private BagTabOverlay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void render(ScreenEvent.Render.Post event) {
|
public static void render(ScreenEvent.Render.Post event) {
|
||||||
if (!(event.getScreen() instanceof InventoryScreen inventoryScreen)) {
|
if (!(event.getScreen() instanceof AbstractContainerScreen<?> screen) || !supportsTabs(screen)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,7 +44,7 @@ public final class BagTabOverlay {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RenderedTab> tabs = getRenderedTabs(inventoryScreen, player);
|
List<RenderedTab> tabs = getRenderedTabs(screen, player);
|
||||||
if (tabs.isEmpty()) {
|
if (tabs.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -65,7 +67,7 @@ public final class BagTabOverlay {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static void mouseClicked(ScreenEvent.MouseButtonPressed.Pre event) {
|
public static void mouseClicked(ScreenEvent.MouseButtonPressed.Pre event) {
|
||||||
if (!(event.getScreen() instanceof InventoryScreen inventoryScreen) || event.getButton() != 0) {
|
if (!(event.getScreen() instanceof AbstractContainerScreen<?> screen) || !supportsTabs(screen) || event.getButton() != 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +76,7 @@ public final class BagTabOverlay {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (RenderedTab tab : getRenderedTabs(inventoryScreen, player)) {
|
for (RenderedTab tab : getRenderedTabs(screen, player)) {
|
||||||
if (tab.isHovered(event.getMouseX(), event.getMouseY())) {
|
if (tab.isHovered(event.getMouseX(), event.getMouseY())) {
|
||||||
PacketDistributor.sendToServer(new OpenBagPayload(tab.entry().slot()));
|
PacketDistributor.sendToServer(new OpenBagPayload(tab.entry().slot()));
|
||||||
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
|
Minecraft.getInstance().getSoundManager().play(SimpleSoundInstance.forUI(SoundEvents.UI_BUTTON_CLICK, 1.0F));
|
||||||
@@ -87,37 +89,74 @@ public final class BagTabOverlay {
|
|||||||
private static List<RenderedTab> getRenderedTabs(AbstractContainerScreen<?> screen, Player player) {
|
private static List<RenderedTab> getRenderedTabs(AbstractContainerScreen<?> screen, Player player) {
|
||||||
List<BagEntry> bags = BagAccess.findBags(player);
|
List<BagEntry> bags = BagAccess.findBags(player);
|
||||||
List<RenderedTab> renderedTabs = new ArrayList<>();
|
List<RenderedTab> renderedTabs = new ArrayList<>();
|
||||||
int x = screen.getGuiLeft() + TAB_X_OFFSET;
|
int activeBagSlot = getActiveBagSlot(screen);
|
||||||
|
int leftBound = getInventoryLeftBound(screen, player);
|
||||||
|
int rightBound = getInventoryRightBound(screen, player);
|
||||||
|
int x = leftBound + TAB_X_OFFSET;
|
||||||
int y = screen.getGuiTop() + screen.getYSize() + TAB_Y_OFFSET;
|
int y = screen.getGuiTop() + screen.getYSize() + TAB_Y_OFFSET;
|
||||||
int maxX = screen.getGuiLeft() + screen.getXSize() - TAB_WIDTH;
|
int maxX = rightBound - TAB_WIDTH;
|
||||||
|
|
||||||
for (BagEntry bag : bags) {
|
for (BagEntry bag : bags) {
|
||||||
if (x > maxX) {
|
if (x > maxX) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderedTabs.add(new RenderedTab(bag, x, y));
|
renderedTabs.add(new RenderedTab(bag, x, y, bag.slot() == activeBagSlot));
|
||||||
x += TAB_WIDTH + TAB_GAP;
|
x += TAB_WIDTH + TAB_GAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
return renderedTabs;
|
return renderedTabs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static int getInventoryLeftBound(AbstractContainerScreen<?> screen, Player player) {
|
||||||
|
return screen.getGuiLeft() + getPlayerInventorySlots(screen, player).stream()
|
||||||
|
.mapToInt(slot -> slot.x)
|
||||||
|
.min()
|
||||||
|
.orElse(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getInventoryRightBound(AbstractContainerScreen<?> screen, Player player) {
|
||||||
|
return screen.getGuiLeft() + getPlayerInventorySlots(screen, player).stream()
|
||||||
|
.mapToInt(slot -> slot.x + 16)
|
||||||
|
.max()
|
||||||
|
.orElse(screen.getXSize() - 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<Slot> getPlayerInventorySlots(AbstractContainerScreen<?> screen, Player player) {
|
||||||
|
List<Slot> slots = screen.getMenu().slots.stream()
|
||||||
|
.filter(slot -> slot.container == player.getInventory())
|
||||||
|
.toList();
|
||||||
|
return slots.isEmpty() ? screen.getMenu().slots : slots;
|
||||||
|
}
|
||||||
|
|
||||||
private static void renderTab(GuiGraphics guiGraphics, RenderedTab tab, int mouseX, int mouseY) {
|
private static void renderTab(GuiGraphics guiGraphics, RenderedTab tab, int mouseX, int mouseY) {
|
||||||
boolean hovered = tab.isHovered(mouseX, mouseY);
|
boolean hovered = tab.isHovered(mouseX, mouseY);
|
||||||
|
boolean selected = tab.selected();
|
||||||
int color = DyedItemColor.getOrDefault(tab.entry().stack(), BagItem.DEFAULT_COLOR);
|
int color = DyedItemColor.getOrDefault(tab.entry().stack(), BagItem.DEFAULT_COLOR);
|
||||||
float red = ((color >> 16) & 0xFF) / 255.0F;
|
float red = ((color >> 16) & 0xFF) / 255.0F;
|
||||||
float green = ((color >> 8) & 0xFF) / 255.0F;
|
float green = ((color >> 8) & 0xFF) / 255.0F;
|
||||||
float blue = (color & 0xFF) / 255.0F;
|
float blue = (color & 0xFF) / 255.0F;
|
||||||
int uOffset = hovered ? TAB_WIDTH : 0;
|
int uOffset = (hovered || selected) ? TAB_WIDTH : 0;
|
||||||
|
|
||||||
RenderSystem.setShaderColor(red, green, blue, 1.0F);
|
RenderSystem.setShaderColor(red, green, blue, 1.0F);
|
||||||
guiGraphics.blit(TAB_BASE_TEXTURE, tab.x(), tab.y(), uOffset, 0, TAB_WIDTH, TAB_HEIGHT, TAB_WIDTH * 2, TAB_HEIGHT);
|
guiGraphics.blit(TAB_BASE_TEXTURE, tab.x(), tab.y(), uOffset, 0, TAB_WIDTH, TAB_HEIGHT, TAB_WIDTH * 2, TAB_HEIGHT);
|
||||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F);
|
||||||
guiGraphics.blit(TAB_OVERLAY_TEXTURE, tab.x(), tab.y(), uOffset, 0, TAB_WIDTH, TAB_HEIGHT, TAB_WIDTH * 2, TAB_HEIGHT);
|
guiGraphics.blit(TAB_OVERLAY_TEXTURE, tab.x(), tab.y(), uOffset, 0, TAB_WIDTH, TAB_HEIGHT, TAB_WIDTH * 2, TAB_HEIGHT);
|
||||||
|
|
||||||
|
if (selected) {
|
||||||
|
guiGraphics.fill(tab.x() + 2, tab.y() + 2, tab.x() + TAB_WIDTH - 2, tab.y() + 4, 0x90FFFFFF);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private record RenderedTab(BagEntry entry, int x, int y) {
|
private static boolean supportsTabs(AbstractContainerScreen<?> screen) {
|
||||||
|
return screen instanceof net.minecraft.client.gui.screens.inventory.InventoryScreen || BagCompat.supportsMenu(screen.getMenu());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getActiveBagSlot(AbstractContainerScreen<?> screen) {
|
||||||
|
return BagCompat.getActiveBagSlot(screen.getMenu());
|
||||||
|
}
|
||||||
|
|
||||||
|
private record RenderedTab(BagEntry entry, int x, int y, boolean selected) {
|
||||||
private boolean isHovered(double mouseX, double mouseY) {
|
private boolean isHovered(double mouseX, double mouseY) {
|
||||||
return mouseX >= this.x && mouseX < this.x + TAB_WIDTH && mouseY >= this.y && mouseY < this.y + TAB_HEIGHT;
|
return mouseX >= this.x && mouseX < this.x + TAB_WIDTH && mouseY >= this.y && mouseY < this.y + TAB_HEIGHT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.trunksbomb.bagtabs.network;
|
package com.trunksbomb.bagtabs.network;
|
||||||
|
|
||||||
import com.trunksbomb.bagtabs.BagTabs;
|
import com.trunksbomb.bagtabs.BagTabs;
|
||||||
|
import com.trunksbomb.bagtabs.bag.BagCompat;
|
||||||
import com.trunksbomb.bagtabs.bag.InventoryBag;
|
import com.trunksbomb.bagtabs.bag.InventoryBag;
|
||||||
import net.minecraft.network.RegistryFriendlyByteBuf;
|
import net.minecraft.network.RegistryFriendlyByteBuf;
|
||||||
import net.minecraft.network.codec.ByteBufCodecs;
|
import net.minecraft.network.codec.ByteBufCodecs;
|
||||||
@@ -33,8 +34,9 @@ public record OpenBagPayload(int slot) implements CustomPacketPayload {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ItemStack stack = serverPlayer.getInventory().getItem(payload.slot());
|
ItemStack stack = serverPlayer.getInventory().getItem(payload.slot());
|
||||||
if (stack.getItem() instanceof InventoryBag inventoryBag) {
|
BagCompat.BagHandler handler = BagCompat.findHandler(stack);
|
||||||
inventoryBag.openFromInventory(serverPlayer, payload.slot());
|
if (handler != null) {
|
||||||
|
handler.open(serverPlayer, payload.slot(), stack);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user