Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.gui.screens;

import meteordevelopment.meteorclient.systems.modules.Modules;
import meteordevelopment.meteorclient.systems.modules.render.BetterTooltips;
import meteordevelopment.meteorclient.utils.Utils;
import net.minecraft.client.gl.RenderPipelines;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.BundleContentsComponent;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.item.BundleItem;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.MathHelper;
import org.lwjgl.glfw.GLFW;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import static meteordevelopment.meteorclient.MeteorClient.mc;

/*
* i couldn't figure out how to add proper outer borders for the GUI without adding custom textures. @TODO
*/
public class ContainerInventoryScreen extends Screen {
private static final Identifier SLOT_TEXTURE = Identifier.ofVanilla("container/slot");
private static final int SLOT_SIZE = 18;
private static final int SCREEN_WIDTH = 176;

private final List<ItemStack> containerItems;
private final PlayerInventory playerInventory;
private final int containerRows;
private int x, y;

private int baseX, baseY;
private int playerY;

public ContainerInventoryScreen(ItemStack containerItem) {
super(containerItem.getName());
this.playerInventory = mc.player.getInventory();

this.containerItems = new ArrayList<>();
if (containerItem.getItem() instanceof BundleItem) {
BundleContentsComponent bundleContents = containerItem.get(DataComponentTypes.BUNDLE_CONTENTS);
if (bundleContents != null) {
bundleContents.iterate().forEach(containerItems::add);
}
} else {
ItemStack[] tempItems = new ItemStack[64];
Utils.getItemsInContainerItem(containerItem, tempItems);
Collections.addAll(containerItems, tempItems);
}

this.containerRows = Math.max(1, MathHelper.ceilDiv(containerItems.size(), 9));
}

@Override
protected void init() {
super.init();
this.x = (this.width - SCREEN_WIDTH) / 2;
this.y = (this.height - (114 + containerRows * SLOT_SIZE + 20)) / 2;
}

@Override
public void render(DrawContext context, int mouseX, int mouseY, float delta) {
super.render(context, mouseX, mouseY, delta);

baseX = x + 8;
baseY = y + 18;
playerY = baseY + containerRows * SLOT_SIZE + 20;

// drawing the slot textures
for (int row = 0; row < containerRows + 4; row++) {
for (int col = 0; col < 9; col++) {
int slotY = row < containerRows ? baseY + row * SLOT_SIZE : playerY + (row - containerRows) * SLOT_SIZE;
context.drawGuiTexture(RenderPipelines.GUI_TEXTURED, SLOT_TEXTURE, baseX + col * SLOT_SIZE, slotY, SLOT_SIZE, SLOT_SIZE);
}
}

// drawing the container items
for (int i = 0; i < containerItems.size(); i++) {
ItemStack item = containerItems.get(i);
if (!item.isEmpty()) {
int itemX = baseX + (i % 9) * SLOT_SIZE + 1;
int itemY = baseY + (i / 9) * SLOT_SIZE + 1;
context.drawItem(item, itemX, itemY);
context.drawStackOverlay(textRenderer, item, itemX, itemY);
}
}

// drawing your inventory items
for (int row = 0; row < 4; row++) {
for (int col = 0; col < 9; col++) {
int slotIndex = row < 3 ? 9 + row * 9 + col : col;
ItemStack item = playerInventory.getStack(slotIndex);
if (!item.isEmpty()) {
int itemX = baseX + col * SLOT_SIZE + 1;
int itemY = playerY + row * SLOT_SIZE + 1;
context.drawItem(item, itemX, itemY);
context.drawStackOverlay(textRenderer, item, itemX, itemY);
}
}
}

// drawing title headers
context.getMatrices().pushMatrix();
context.getMatrices().translate((float) x, (float) y);
if (textRenderer != null) {
context.drawText(textRenderer, title, 8, 6, -12566464, false);
context.drawText(textRenderer, playerInventory.getDisplayName(), 8, 18 + containerRows * SLOT_SIZE + 10, -12566464, false);
}
context.getMatrices().popMatrix();

// drawing the tooltip
ItemStack item = getSelectedItem(mouseX, mouseY);
if (!item.isEmpty()) {
context.drawTooltip(textRenderer, getTooltipFromItem(mc, item), item.getTooltipData(), mouseX, mouseY);
}
}

@Override
public boolean mouseClicked(double mouseX, double mouseY, int button) {
BetterTooltips tooltips = Modules.get().get(BetterTooltips.class);

ItemStack stack = getSelectedItem((int) mouseX, (int) mouseY);
if (tooltips.shouldOpenContents(false, button, 0)) {
return tooltips.openContent(stack);
}

return false;
}

@Override
public boolean keyPressed(int keyCode, int scanCode, int modifiers) {
BetterTooltips tooltips = Modules.get().get(BetterTooltips.class);

ItemStack stack = getSelectedItem((int) mc.mouse.getScaledX(mc.getWindow()), (int) mc.mouse.getScaledY(mc.getWindow()));
if (tooltips.shouldOpenContents(true, keyCode, modifiers)) {
return tooltips.openContent(stack);
}

if (keyCode == GLFW.GLFW_KEY_ESCAPE || mc.options.inventoryKey.matchesKey(keyCode, scanCode)) {
close();
return true;
}

return false;
}

private ItemStack getSelectedItem(int mouseX, int mouseY) {
if (mouseX < baseX || mouseX > baseX + 9 * SLOT_SIZE) return ItemStack.EMPTY;

int col = (mouseX - baseX) / SLOT_SIZE;
if (col > 8) return ItemStack.EMPTY;

if (mouseY >= baseY && mouseY < baseY + containerRows * SLOT_SIZE) {
int index = ((mouseY - baseY) / SLOT_SIZE) * 9 + col;
return (index < containerItems.size() ? containerItems.get(index) : ItemStack.EMPTY);
}

if (mouseY >= playerY && mouseY < playerY + 4 * SLOT_SIZE) {
int row = (mouseY - playerY) / SLOT_SIZE;
int slotIndex = row < 3 ? 9 + row * 9 + col : col;
return playerInventory.getStack(slotIndex);
}

return ItemStack.EMPTY;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.mixin;

import meteordevelopment.meteorclient.MeteorClient;
import meteordevelopment.meteorclient.events.render.TooltipDataEvent;
import net.minecraft.item.BundleItem;
import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipData;
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.callback.CallbackInfoReturnable;

import java.util.Optional;

@Mixin(BundleItem.class)
public class BundleItemMixin {
@Inject(method = "getTooltipData", at = @At("HEAD"), cancellable = true)
private void onTooltipData(ItemStack stack, CallbackInfoReturnable<Optional<TooltipData>> cir) {
TooltipDataEvent event = MeteorClient.EVENT_BUS.post(TooltipDataEvent.get(stack));
if (event.tooltipData != null) {
cir.setReturnValue(Optional.of(event.tooltipData));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client).
* Copyright (c) Meteor Development.
*/

package meteordevelopment.meteorclient.mixin;

import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import meteordevelopment.meteorclient.systems.modules.Modules;
import meteordevelopment.meteorclient.systems.modules.misc.InventoryTweaks;
import net.minecraft.client.gui.tooltip.BundleTooltipSubmenuHandler;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.component.type.BundleContentsComponent;
import net.minecraft.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;

@Mixin(BundleTooltipSubmenuHandler.class)
public class BundleTooltipSubmenuHandlerMixin {
@ModifyExpressionValue(method = "sendPacket", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BundleItem;getNumberOfStacksShown(Lnet/minecraft/item/ItemStack;)I"))
private int uncapBundleScrolling1(int original, ItemStack item, int slotId, int selectedItemIndex) {
if (Modules.get().get(InventoryTweaks.class).uncapBundleScrolling()) return item.getOrDefault(DataComponentTypes.BUNDLE_CONTENTS, BundleContentsComponent.DEFAULT).size();
return original;
}

@ModifyExpressionValue(method = "onScroll", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/BundleItem;getNumberOfStacksShown(Lnet/minecraft/item/ItemStack;)I"))
private int uncapBundleScrolling2(int original, double horizontal, double vertical, int slotId, ItemStack item) {
if (Modules.get().get(InventoryTweaks.class).uncapBundleScrolling()) return item.getOrDefault(DataComponentTypes.BUNDLE_CONTENTS, BundleContentsComponent.DEFAULT).size();
return original;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,30 @@

package meteordevelopment.meteorclient.mixin;

import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import meteordevelopment.meteorclient.systems.modules.Modules;
import meteordevelopment.meteorclient.systems.modules.misc.InventoryTweaks;
import meteordevelopment.meteorclient.systems.modules.render.BetterTooltips;
import meteordevelopment.meteorclient.systems.modules.render.ItemHighlight;
import meteordevelopment.meteorclient.utils.Utils;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.BookScreen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.gui.screen.ingame.ScreenHandlerProvider;
import net.minecraft.client.gui.tooltip.TooltipComponent;
import net.minecraft.client.gui.widget.ButtonWidget;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.screen.ScreenHandler;
import net.minecraft.screen.slot.Slot;
import net.minecraft.screen.slot.SlotActionType;
import net.minecraft.text.Text;
import org.jetbrains.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import static meteordevelopment.meteorclient.MeteorClient.mc;
import static org.lwjgl.glfw.GLFW.GLFW_MOUSE_BUTTON_LEFT;

@Mixin(HandledScreen.class)
Expand Down Expand Up @@ -62,9 +57,6 @@ public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen
@Shadow
public abstract void close();

@Unique
private static final ItemStack[] ITEMS = new ItemStack[27];

public HandledScreenMixin(Text title) {
super(title);
}
Expand Down Expand Up @@ -104,14 +96,20 @@ private void onMouseDragged(double mouseX, double mouseY, int button, double del
private void mouseClicked(double mouseX, double mouseY, int button, CallbackInfoReturnable<Boolean> cir) {
BetterTooltips tooltips = Modules.get().get(BetterTooltips.class);

if (button == GLFW.GLFW_MOUSE_BUTTON_MIDDLE && focusedSlot != null && !focusedSlot.getStack().isEmpty() && getScreenHandler().getCursorStack().isEmpty() && tooltips.middleClickOpen()) {
ItemStack itemStack = focusedSlot.getStack();
if (Utils.hasItems(itemStack) || itemStack.getItem() == Items.ENDER_CHEST) {
cir.setReturnValue(Utils.openContainer(focusedSlot.getStack(), ITEMS, false));
if (tooltips.shouldOpenContents(false, button, 0) && focusedSlot != null && !focusedSlot.getStack().isEmpty() && getScreenHandler().getCursorStack().isEmpty()) {
if (tooltips.openContent(focusedSlot.getStack())) {
cir.setReturnValue(true);
}
else if (itemStack.get(DataComponentTypes.WRITTEN_BOOK_CONTENT) != null || itemStack.get(DataComponentTypes.WRITABLE_BOOK_CONTENT) != null) {
close();
mc.setScreen(new BookScreen(BookScreen.Contents.create(itemStack)));
}
}

// Keyboard input for middle click open
@Inject(method = "keyPressed", at = @At("HEAD"), cancellable = true)
private void keyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
BetterTooltips tooltips = Modules.get().get(BetterTooltips.class);

if (tooltips.shouldOpenContents(true, keyCode, modifiers) && focusedSlot != null && !focusedSlot.getStack().isEmpty() && getScreenHandler().getCursorStack().isEmpty()) {
if (tooltips.openContent(focusedSlot.getStack())) {
cir.setReturnValue(true);
}
}
Expand All @@ -123,4 +121,13 @@ private void onDrawSlot(DrawContext context, Slot slot, CallbackInfo ci) {
int color = Modules.get().get(ItemHighlight.class).getColor(slot.getStack());
if (color != -1) context.fill(slot.x, slot.y, slot.x + 16, slot.y + 16, color);
}

@ModifyReturnValue(method = "isItemTooltipSticky", at = @At("RETURN"))
private boolean isTooltipSticky(boolean original, ItemStack item) {
if (item.getTooltipData().orElse(null) instanceof TooltipComponent component) {
return original || component.isSticky();
}

return original;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

import meteordevelopment.meteorclient.MeteorClient;
import meteordevelopment.meteorclient.events.render.TooltipDataEvent;

import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.tooltip.TooltipData;
Expand All @@ -20,7 +19,7 @@

@Mixin(Item.class)
public abstract class ItemMixin {
@Inject(method = "getTooltipData", at=@At("HEAD"), cancellable = true)
@Inject(method = "getTooltipData", at = @At("HEAD"), cancellable = true)
private void onTooltipData(ItemStack stack, CallbackInfoReturnable<Optional<TooltipData>> cir) {
TooltipDataEvent event = MeteorClient.EVENT_BUS.post(TooltipDataEvent.get(stack));
if (event.tooltipData != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ public class InventoryTweaks extends Module {
.build()
);

private final Setting<Boolean> uncapBundleScrolling = sgGeneral.add(new BoolSetting.Builder()
.name("uncap-bundle-scrolling")
.description("Whether to uncap the bundle scrolling feature to let you select any item.")
.defaultValue(true)
.build()
);

// Anti drop

private final Setting<List<Item>> antiDropItems = sgAntiDrop.add(new ItemListSetting.Builder()
Expand Down Expand Up @@ -452,6 +459,10 @@ public boolean mouseDragItemMove() {
return isActive() && mouseDragItemMove.get();
}

public boolean uncapBundleScrolling() {
return isActive() && uncapBundleScrolling.get();
}

public boolean canSteal(ScreenHandler handler) {
try {
return (stealScreens.get().contains(handler.getType()));
Expand Down
Loading