Skip to content

Commit

Permalink
Refactor Backpack Preview
Browse files Browse the repository at this point in the history
  • Loading branch information
kevinthegreat1 committed Oct 26, 2023
1 parent 44a35de commit 6c8b6df
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 119 deletions.
31 changes: 16 additions & 15 deletions src/main/java/de/hysky/skyblocker/mixin/HandledScreenMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,15 +41,15 @@
@Mixin(HandledScreen.class)
public abstract class HandledScreenMixin<T extends ScreenHandler> extends Screen {
/**
* This is the slot id returned for when a click is outside of the screen's bounds
* This is the slot id returned for when a click is outside the screen's bounds
*/
@Unique
private static final int OUT_OF_BOUNDS_SLOT = -999;

@Shadow
@Nullable
protected Slot focusedSlot;

@Shadow
@Final
protected T handler;
Expand Down Expand Up @@ -78,7 +78,7 @@ protected HandledScreenMixin(Text title) {

// Backpack Preview
boolean shiftDown = SkyblockerConfigManager.get().general.backpackPreviewWithoutShift ^ Screen.hasShiftDown();
if (shiftDown && getTitle().getString().equals("Storage") && focusedSlot.inventory != client.player.getInventory() && BackpackPreview.renderPreview(context, focusedSlot.getIndex(), x, y)) {
if (shiftDown && getTitle().getString().equals("Storage") && focusedSlot.inventory != client.player.getInventory() && BackpackPreview.renderPreview(context, this, focusedSlot.getIndex(), x, y)) {
ci.cancel();
}

Expand Down Expand Up @@ -133,57 +133,58 @@ protected HandledScreenMixin(Text title) {
}
}
}

/**
* The naming of this method in yarn is half true, its mostly to handle slot/item interactions (which are mouse or keyboard clicks)
* For example, using the drop key bind while hovering over an item will invoke this method to drop the players item
*/
@Inject(method = "onMouseClick(Lnet/minecraft/screen/slot/Slot;IILnet/minecraft/screen/slot/SlotActionType;)V", at = @At("HEAD"), cancellable = true)
private void skyblocker$onSlotInteract(Slot slot, int slotId, int button, SlotActionType actionType, CallbackInfo ci) {
if (Utils.isOnSkyblock()) {
if (Utils.isOnSkyblock()) {
// When you try and drop the item by picking it up then clicking outside of the screen
if (slotId == OUT_OF_BOUNDS_SLOT) {
ItemStack cursorStack = this.handler.getCursorStack();

if (ItemProtection.isItemProtected(cursorStack)) ci.cancel();
}

if (slot != null) {
// When you click your drop key while hovering over an item
if (actionType == SlotActionType.THROW) {
ItemStack stack = slot.getStack();

if (ItemProtection.isItemProtected(stack)) ci.cancel();
}

//Prevent salvaging
if (this.getTitle().getString().equals("Salvage Items")) {
ItemStack stack = slot.getStack();

if (ItemProtection.isItemProtected(stack)) ci.cancel();
}

//Prevent selling to NPC shops
if (this.client != null && this.handler instanceof GenericContainerScreenHandler genericContainerScreenHandler && genericContainerScreenHandler.getRows() == 6) {
ItemStack sellItem = this.handler.slots.get(49).getStack();

if (sellItem.getName().getString().equals("Sell Item") || skyblocker$doesLoreContain(sellItem, this.client, "buyback")) {
ItemStack stack = slot.getStack();

if (ItemProtection.isItemProtected(stack)) ci.cancel();
}
}
}
}
}
}

//TODO make this a util method somewhere else, eventually
private static boolean skyblocker$doesLoreContain(ItemStack stack, MinecraftClient client, String searchString) {
return stack.getTooltip(client.player, TooltipContext.BASIC).stream().map(Text::getString).anyMatch(line -> line.contains(searchString));
}

@Inject(method = "drawSlot", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/DrawContext;drawItem(Lnet/minecraft/item/ItemStack;III)V"))
private void skyblocker$drawItemRarityBackground(DrawContext context, Slot slot, CallbackInfo ci) {
if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) ItemRarityBackgrounds.tryDraw(slot.getStack(), context, slot.x, slot.y);
if (Utils.isOnSkyblock() && SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds)
ItemRarityBackgrounds.tryDraw(slot.getStack(), context, slot.x, slot.y);
}
}
160 changes: 56 additions & 104 deletions src/main/java/de/hysky/skyblocker/skyblock/item/BackpackPreview.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,18 +11,17 @@
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.inventory.SimpleInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.*;
import net.minecraft.util.Identifier;
import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
Expand Down Expand Up @@ -51,15 +50,16 @@ public static void tick() {
Utils.update(); // force update isOnSkyblock to prevent crash on disconnect
if (Utils.isOnSkyblock()) {
// save all dirty storages
saveStorage();
saveStorages();
// update save dir based on uuid and sb profile
String uuid = MinecraftClient.getInstance().getSession().getUuidOrNull().toString().replaceAll("-", "");
String profile = Utils.getProfile();
String profile = Utils.getProfile(); //TODO switch to profile id
if (!profile.isEmpty()) {
save_dir = FabricLoader.getInstance().getConfigDir().resolve("skyblocker/backpack-preview/" + uuid + "/" + profile);
String loading = uuid + "/" + profile;
save_dir = FabricLoader.getInstance().getConfigDir().resolve("skyblocker/backpack-preview/" + loading);
//noinspection ResultOfMethodCallIgnored
save_dir.toFile().mkdirs();
if (loaded.equals(uuid + "/" + profile)) {
if (loaded.equals(loading)) {
// mark currently opened storage as dirty
if (MinecraftClient.getInstance().currentScreen != null) {
String title = MinecraftClient.getInstance().currentScreen.getTitle().getString();
Expand All @@ -68,61 +68,45 @@ public static void tick() {
}
} else {
// load storage again because uuid/profile changed
loaded = uuid + "/" + profile;
loadStorage();
loaded = loading;
loadStorages();
}
}
}
}

public static void loadStorage() {
public static void loadStorages() {
assert (save_dir != null);
for (int index = 0; index < STORAGE_SIZE; ++index) {
storages[index] = null;
File file = save_dir.resolve(index + ".nbt").toFile();
if (file.isFile()) {
try {
NbtCompound root = NbtIo.read(file);
storages[index] = new Storage(new DummyInventory(Objects.requireNonNull(root)), root.getString("name"));
storages[index] = Storage.fromNbt(Objects.requireNonNull(NbtIo.read(file)));
} catch (Exception e) {
LOGGER.error("Failed to load backpack preview file: " + file.getName(), e);
}
}
}
}

private static void saveStorage() {
private static void saveStorages() {
assert (save_dir != null);
for (int index = 0; index < STORAGE_SIZE; ++index) {
if (storages[index] != null && storages[index].dirty) {
try {
NbtCompound root = new NbtCompound();
NbtList list = new NbtList();
for (int i = 9; i < storages[index].inventory.size(); ++i) {
ItemStack stack = storages[index].inventory.getStack(i);
NbtCompound item = new NbtCompound();
if (stack.isEmpty()) {
item.put("id", NbtString.of("minecraft:air"));
item.put("Count", NbtInt.of(1));
} else {
item.put("id", NbtString.of(stack.getItem().toString()));
item.put("Count", NbtInt.of(stack.getCount()));
item.put("tag", stack.getNbt());
}
list.add(item);
}
root.put("list", list);
root.put("size", NbtInt.of(storages[index].inventory.size() - 9));
root.putString("name", storages[index].name);
NbtIo.write(root, save_dir.resolve(index + ".nbt").toFile());
storages[index].markClean();
} catch (Exception e) {
LOGGER.error("Failed to save backpack preview file: " + index + ".nbt", e);
}
saveStorage(index);
}
}
}

private static void saveStorage(int index) {
try {
NbtIo.write(storages[index].toNbt(), save_dir.resolve(index + ".nbt").toFile());
storages[index].markClean();
} catch (Exception e) {
LOGGER.error("Failed to save backpack preview file: " + index + ".nbt", e);
}
}

public static void updateStorage(HandledScreen<?> screen) {
String title = screen.getTitle().getString();
int index = getStorageIndexFromTitle(title);
Expand All @@ -131,16 +115,14 @@ public static void updateStorage(HandledScreen<?> screen) {
}
}

public static boolean renderPreview(DrawContext context, int index, int mouseX, int mouseY) {
public static boolean renderPreview(DrawContext context, Screen screen, int index, int mouseX, int mouseY) {
if (index >= 9 && index < 18) index -= 9;
else if (index >= 27 && index < 45) index -= 18;
else return false;

if (storages[index] == null) return false;
int rows = (storages[index].inventory.size() - 9) / 9;
int rows = (storages[index].size() - 9) / 9;

Screen screen = MinecraftClient.getInstance().currentScreen;
if (screen == null) return false;
int x = mouseX + 184 >= screen.width ? mouseX - 188 : mouseX + 8;
int y = Math.max(0, mouseY - 16);

Expand All @@ -149,27 +131,24 @@ public static boolean renderPreview(DrawContext context, int index, int mouseX,
matrices.translate(0f, 0f, 400f);

RenderSystem.enableDepthTest();
context.drawTexture(TEXTURE, x, y, 0, 0, 176, 7);
context.drawTexture(TEXTURE, x, y + 7, 0, 17, 176, rows * 18);
context.drawTexture(TEXTURE, x, y + rows * 18 + 7, 0, 215, 176, 7);
context.drawTexture(TEXTURE, x, y, 0, 0, 176, rows * 18 + 17);
context.drawTexture(TEXTURE, x, y + rows * 18 + 17, 0, 215, 176, 7);

TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
context.drawText(textRenderer, storages[index].name, x + 8, y + 6, 0x404040, false);

for (int i = 9; i < storages[index].inventory.size(); ++i) {
ItemStack currentStack = storages[index].inventory.getStack(i);
matrices.translate(0f, 0f, 200f);
for (int i = 9; i < storages[index].size(); ++i) {
ItemStack currentStack = storages[index].getStack(i);
int itemX = x + (i - 9) % 9 * 18 + 8;
int itemY = y + (i - 9) / 9 * 18 + 8;
int itemY = y + (i - 9) / 9 * 18 + 18;

if (SkyblockerConfigManager.get().general.itemInfoDisplay.itemRarityBackgrounds) {
ItemRarityBackgrounds.tryDraw(currentStack, context, itemX, itemY);
}

matrices.push();
matrices.translate(0f, 0f, 200f);
context.drawItem(currentStack, itemX, itemY);
context.drawItemInSlot(textRenderer, currentStack, itemX, itemY);
matrices.pop();
}

matrices.pop();
Expand All @@ -190,77 +169,50 @@ static class Storage {
private final String name;
private boolean dirty;

public Storage(Inventory inventory, String name) {
private Storage(Inventory inventory, String name) {
this(inventory, name, false);
}

public Storage(Inventory inventory, String name, boolean dirty) {
private Storage(Inventory inventory, String name, boolean dirty) {
this.inventory = inventory;
this.name = name;
this.dirty = dirty;
}

public void markDirty() {
dirty = true;
}

public void markClean() {
dirty = false;
}
}

static class DummyInventory implements Inventory {
private final List<ItemStack> stacks;

public DummyInventory(NbtCompound root) {
stacks = new ArrayList<>(root.getInt("size") + 9);
for (int i = 0; i < 9; ++i) stacks.add(ItemStack.EMPTY);
root.getList("list", NbtCompound.COMPOUND_TYPE).forEach(item ->
stacks.add(ItemStack.fromNbt((NbtCompound) item))
);
}

@Override
public int size() {
return stacks.size();
private int size() {
return inventory.size();
}

@Override
public boolean isEmpty() {
return false;
private ItemStack getStack(int index) {
return inventory.getStack(index);
}

@Override
public ItemStack getStack(int slot) {
return stacks.get(slot);
}

@Override
public ItemStack removeStack(int slot, int amount) {
return null;
}

@Override
public ItemStack removeStack(int slot) {
return null;
}

@Override
public void setStack(int slot, ItemStack stack) {
stacks.set(slot, stack);
private void markDirty() {
dirty = true;
}

@Override
public void markDirty() {
private void markClean() {
dirty = false;
}

@Override
public boolean canPlayerUse(PlayerEntity player) {
return false;
@NotNull
private static Storage fromNbt(NbtCompound root) {
SimpleInventory inventory = new SimpleInventory(root.getInt("size"));
inventory.readNbtList(root.getList("list", NbtCompound.COMPOUND_TYPE));
return new Storage(inventory, root.getString("name"));
}

@Override
public void clear() {
@NotNull
private NbtCompound toNbt() {
NbtCompound root = new NbtCompound();
NbtList list = new NbtList();
for (int i = 0; i < size(); ++i) {
list.add(getStack(i).writeNbt(new NbtCompound()));
}
root.put("list", list);
root.put("size", NbtInt.of(size()));
root.putString("name", name);
return root;
}
}
}

0 comments on commit 6c8b6df

Please sign in to comment.