Skip to content

Commit

Permalink
rework backpack inventory (fixes #29)
Browse files Browse the repository at this point in the history
  • Loading branch information
UpcraftLP committed Jan 3, 2024
1 parent d99ba11 commit 3583cc1
Show file tree
Hide file tree
Showing 10 changed files with 362 additions and 190 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package dev.cammiescorner.camsbackpacks;

import com.google.common.base.MoreObjects;
import dev.cammiescorner.camsbackpacks.common.network.EquipBackpackPacket;
import dev.cammiescorner.camsbackpacks.common.network.OpenBackpackScreenPacket;
import dev.cammiescorner.camsbackpacks.common.network.PlaceBackpackPacket;
Expand All @@ -11,7 +12,9 @@
import eu.midnightdust.lib.config.MidnightConfig;
import net.minecraft.resources.ResourceLocation;
import org.quiltmc.loader.api.ModContainer;
import org.quiltmc.loader.api.ModMetadata;
import org.quiltmc.loader.api.QuiltLoader;
import org.quiltmc.loader.api.plugin.ModMetadataExt;
import org.quiltmc.qsl.base.api.entrypoint.ModInitializer;
import org.quiltmc.qsl.networking.api.ServerPlayNetworking;

Expand All @@ -38,4 +41,8 @@ public void onInitialize(ModContainer mod) {
public static ResourceLocation id(String path) {
return new ResourceLocation(MOD_ID, path);
}

public static String getIssuesURL() {
return QuiltLoader.getModContainer(MOD_ID).map(ModContainer::metadata).map(meta -> meta.getContactInfo("issues")).orElse(MOD_ID);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import dev.cammiescorner.camsbackpacks.CamsBackpacks;
import dev.cammiescorner.camsbackpacks.client.CamsBackpacksClient;
import dev.cammiescorner.camsbackpacks.common.network.EquipBackpackPacket;
import dev.cammiescorner.camsbackpacks.common.screen.BackpackScreenHandler;
import dev.cammiescorner.camsbackpacks.common.menu.BackpackMenu;
import dev.cammiescorner.camsbackpacks.core.util.BackpackHelper;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
Expand All @@ -25,7 +25,7 @@
import org.lwjgl.glfw.GLFW;

@SuppressWarnings("ConstantConditions")
public class BackpackScreen extends EffectRenderingInventoryScreen<BackpackScreenHandler> {
public class BackpackScreen extends EffectRenderingInventoryScreen<BackpackMenu> {
public static final ResourceLocation TEXTURE = CamsBackpacks.id("textures/gui/backpack.png");
protected Inventory playerInventory;
protected Button equipButton;
Expand All @@ -37,7 +37,7 @@ public class BackpackScreen extends EffectRenderingInventoryScreen<BackpackScree
protected int playerNameX;
protected int playerNameY;

public BackpackScreen(BackpackScreenHandler screenHandler, Inventory playerInventory, Component text) {
public BackpackScreen(BackpackMenu screenHandler, Inventory playerInventory, Component text) {
super(screenHandler, playerInventory, text);
this.playerInventory = playerInventory;
this.imageWidth = 322;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package dev.cammiescorner.camsbackpacks.common.blocks.entities;

import dev.cammiescorner.camsbackpacks.common.screen.BackpackScreenHandler;
import dev.cammiescorner.camsbackpacks.common.menu.BackpackMenu;
import dev.cammiescorner.camsbackpacks.core.registry.ModBlockEntities;
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
import net.minecraft.core.BlockPos;
Expand Down Expand Up @@ -108,7 +108,7 @@ public Component getDisplayName() {

@Override
public @Nullable AbstractContainerMenu createMenu(int syncId, Inventory inv, Player player) {
return new BackpackScreenHandler(syncId, inv, this, ContainerLevelAccess.create(player.level(), getBlockPos()), getBlockPos(), true);
return new BackpackMenu(syncId, inv, this, ContainerLevelAccess.create(player.level(), getBlockPos()), getBlockPos(), true);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
package dev.cammiescorner.camsbackpacks.common.menu;

import dev.cammiescorner.camsbackpacks.CamsBackpacks;
import dev.cammiescorner.camsbackpacks.common.menu.slot.ArmorSlot;
import dev.cammiescorner.camsbackpacks.common.menu.slot.OffhandSlot;
import dev.cammiescorner.camsbackpacks.core.mixin.accessor.CraftingMenuAccessor;
import dev.cammiescorner.camsbackpacks.core.registry.ModScreenHandlers;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.*;
import net.minecraft.world.item.ItemStack;

import java.util.List;

public class BackpackMenu extends AbstractContainerMenu {

private static final List<EquipmentSlot> ARMOR_SLOTS = List.of(EquipmentSlot.FEET, EquipmentSlot.LEGS, EquipmentSlot.CHEST, EquipmentSlot.HEAD);

private final Player player;
private final Container inventory;
private final TransientCraftingContainer craftingInv;
private final ResultContainer craftingResultInv;
private final ContainerLevelAccess levelAccess;
public final boolean isBlockEntity;
public BlockPos blockPos;

public BackpackMenu(int syncId, Inventory playerInventory, BlockPos blockPos, boolean isBlockEntity) {
this(syncId, playerInventory, new SimpleContainer(36), ContainerLevelAccess.NULL, blockPos, isBlockEntity);
}

public BackpackMenu(int syncId, Inventory playerInventory, Container inventory, ContainerLevelAccess levelAccess, BlockPos blockPos, boolean isBlockEntity) {
super(ModScreenHandlers.BACKPACK_SCREEN_HANDLER, syncId);
checkContainerSize(inventory, 36);
this.player = playerInventory.player;
this.inventory = inventory;
this.craftingInv = new TransientCraftingContainer(this, 3, 3);
this.craftingResultInv = new ResultContainer();
this.levelAccess = levelAccess;
this.blockPos = blockPos;
this.isBlockEntity = isBlockEntity;
inventory.startOpen(player);

// Crafting result (slot 0) (global: 0)
addSlot(new ResultSlot(player, craftingInv, craftingResultInv, 0, 273, 71 + 3 * 18));

// Crafting table inventory (slots 1-9) (global: 1-9)
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 3; ++x) {
addSlot(new Slot(craftingInv, x + y * 3, 255 + x * 18, 46 + y * 18));
}
}

// Backpack inventory (slots 0-35) (global: 10-45)
for (int y = 0; y < 4; ++y) {
for (int x = 0; x < 9; ++x) {
addSlot(new Slot(inventory, x + y * 9, 81 + x * 18, 18 + y * 18));
}
}

// Player inventory (slots 9-35) (global: 46-72)
for (int y = 0; y < 3; ++y) {
for (int x = 0; x < 9; ++x) {
addSlot(new Slot(playerInventory, x + y * 9 + 9, 81 + x * 18, 108 + y * 18));
}
}

// Player hotbar (slots 0-8) (global: 73-82)
for (int i = 0; i < 9; ++i) {
addSlot(new Slot(playerInventory, i, 81 + i * 18, 166));
}

// Player armor (slot 36-39) (global: 82-85)
for (int i = 0; i < ARMOR_SLOTS.size(); ++i) {
EquipmentSlot equipmentSlot = ARMOR_SLOTS.get(i);
addSlot(new ArmorSlot(playerInventory, equipmentSlot.getIndex(36), 8, 105 - i * 18, equipmentSlot, player));
}

// Player offhand (slot 40) (global: 86)
this.addSlot(new OffhandSlot(playerInventory, 40, 8, 123, player));

}

@Override
public void slotsChanged(Container inventory) {
levelAccess.execute((world, pos) -> CraftingMenuAccessor.camsbackpacks$callSlotChangedCraftingGrid(this, world, player, craftingInv, craftingResultInv));
}

@Override
public ItemStack quickMoveStack(Player player, int index) {
ItemStack newStack = ItemStack.EMPTY;
Slot slot = this.slots.get(index);

if (slot.hasItem()) {
ItemStack oldStack = slot.getItem();
newStack = oldStack.copy();

if (index == 0) { // moving out of result slot (0) -> inv first, then backpack, then hotbar
this.levelAccess.execute((world, pos) -> oldStack.getItem().onCraftedBy(oldStack, world, player));

// try player inv
if (!moveItemStackTo(oldStack, 46, 73, false)) {

// try backpack inv
if (!moveItemStackTo(oldStack, 10, 46, false)) {

// try hotbar
if (!moveItemStackTo(oldStack, 73, 82, false)) {
return ItemStack.EMPTY;
}
}
}
slot.onQuickCraft(oldStack, newStack);
} else if (index <= 9) { // moving out of crafting inv (1-9) -> inv first, then backpack, then hotbar

// try player inv
if (!moveItemStackTo(oldStack, 46, 73, false)) {

// try backpack inv
if (!moveItemStackTo(oldStack, 10, 46, false)) {

// try hotbar
if (!moveItemStackTo(oldStack, 73, 82, false)) {
return ItemStack.EMPTY;
}
}
}

} else if (index <= 45) { // moving out of backpack inv (10-45) -> armor inv, then hotbar, then regular inv

// try preferred armor slot
EquipmentSlot equipmentSlot = Mob.getEquipmentSlotForItem(newStack);
int armorSlotId = equipmentSlot.getIndex(82);
if (equipmentSlot.getType() == EquipmentSlot.Type.ARMOR && !getSlot(armorSlotId).hasItem()) {
if (!moveItemStackTo(oldStack, armorSlotId, armorSlotId + 1, false)) {

// try hotbar
if (!moveItemStackTo(oldStack, 73, 82, false)) {

// try player inv
if (!moveItemStackTo(oldStack, 46, 73, true)) {
return ItemStack.EMPTY;
}
}
}
} else {

// try hotbar
if (!moveItemStackTo(oldStack, 73, 82, false)) {

// try player inv
if (!moveItemStackTo(oldStack, 46, 73, true)) {
return ItemStack.EMPTY;
}
}
}

} else if (index <= 72) { // moving out of player inv (46-72) -> backpack inv, then hotbar

// try backpack inv
if (!moveItemStackTo(oldStack, 10, 46, false)) {

// try hotbar
if (!moveItemStackTo(oldStack, 73, 82, true)) {
return ItemStack.EMPTY;
}
}

} else if (index <= 81) { // moving out of hotbar (73-81) -> backpack inv, then player inv

// try backpack inv
if (!moveItemStackTo(oldStack, 10, 46, false)) {

// try player inv
if (!moveItemStackTo(oldStack, 46, 73, false)) {
return ItemStack.EMPTY;
}
}

} else if (index <= 86) { // moving out of armor items (82-85) or offhand (86) -> backpack inv, then player inv, then hotbar

// try backpack inv
if (!moveItemStackTo(oldStack, 10, 46, false)) {

// try player inv
if (!moveItemStackTo(oldStack, 46, 73, false)) {

// try hotbar
if (!moveItemStackTo(oldStack, 73, 82, true)) {
return ItemStack.EMPTY;
}
}
}

} else {
// crash the game so we get bug reports
throw new IllegalArgumentException("[Cammies-Wearable-Backpacks] Tried to quick transfer out of Slot [" + index + "]; please report this to " + CamsBackpacks.getIssuesURL());
}

if (oldStack.isEmpty()) {
slot.setByPlayer(ItemStack.EMPTY);
} else {
slot.setChanged();
}

if (oldStack.getCount() == newStack.getCount()) {
return ItemStack.EMPTY;
}

slot.onTake(player, oldStack);

// can't put back into result slot, so drop remaining items
if (index == 0) {
player.drop(oldStack, false);
}
}

return newStack;
}

@Override
public void removed(Player player) {
super.removed(player);
levelAccess.execute((world, pos) -> {
if (!world.isClientSide() && !isBlockEntity) {
ItemStack stack = player.getItemBySlot(EquipmentSlot.CHEST);
CompoundTag tag = stack.getOrCreateTag();
NonNullList<ItemStack> inv = NonNullList.withSize(36, ItemStack.EMPTY);

for (int i = 0; i < inventory.getContainerSize(); i++)
inv.set(i, inventory.getItem(i));

ContainerHelper.saveAllItems(tag, inv);
}

clearContainer(player, craftingInv);
});
}

@Override
public boolean stillValid(Player player) {
return inventory.stillValid(player);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package dev.cammiescorner.camsbackpacks.common.menu.slot;

import com.mojang.datafixers.util.Pair;
import dev.cammiescorner.camsbackpacks.common.items.BackpackItem;
import dev.cammiescorner.camsbackpacks.core.mixin.accessor.InventoryMenuAccessor;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.InventoryMenu;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.enchantment.EnchantmentHelper;

public class ArmorSlot extends Slot {

private final EquipmentSlot equipmentSlot;
private final Player player;

public ArmorSlot(Inventory playerInventory, int slotIndex, int x, int y, EquipmentSlot equipmentSlot, Player player) {
super(playerInventory, slotIndex, x, y);
this.equipmentSlot = equipmentSlot;
this.player = player;
}

@Override
public void setByPlayer(ItemStack stack) {
InventoryMenuAccessor.camsbackpacks$callOnEquipItem(this.player, this.equipmentSlot, stack, this.getItem());
super.setByPlayer(stack);
}

@Override
public int getMaxStackSize() {
return 1;
}

@Override
public boolean mayPlace(ItemStack stack) {
return equipmentSlot == Mob.getEquipmentSlotForItem(stack);
}

@Override
public boolean mayPickup(Player playerEntity) {
ItemStack stack = getItem();
return (stack.isEmpty() || playerEntity.isCreative() || !EnchantmentHelper.hasBindingCurse(stack)) && !(stack.getItem() instanceof BackpackItem) && super.mayPickup(playerEntity);
}

@Override
public Pair<ResourceLocation, ResourceLocation> getNoItemIcon() {
return Pair.of(InventoryMenu.BLOCK_ATLAS, InventoryMenuAccessor.camsbackpacks$getEmptySlotsTextures()[equipmentSlot.getIndex()]);
}
}
Loading

0 comments on commit 3583cc1

Please sign in to comment.