Skip to content

Commit 3583cc1

Browse files
committed
rework backpack inventory (fixes #29)
1 parent d99ba11 commit 3583cc1

File tree

10 files changed

+362
-190
lines changed

10 files changed

+362
-190
lines changed

src/main/java/dev/cammiescorner/camsbackpacks/CamsBackpacks.java

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package dev.cammiescorner.camsbackpacks;
22

3+
import com.google.common.base.MoreObjects;
34
import dev.cammiescorner.camsbackpacks.common.network.EquipBackpackPacket;
45
import dev.cammiescorner.camsbackpacks.common.network.OpenBackpackScreenPacket;
56
import dev.cammiescorner.camsbackpacks.common.network.PlaceBackpackPacket;
@@ -11,7 +12,9 @@
1112
import eu.midnightdust.lib.config.MidnightConfig;
1213
import net.minecraft.resources.ResourceLocation;
1314
import org.quiltmc.loader.api.ModContainer;
15+
import org.quiltmc.loader.api.ModMetadata;
1416
import org.quiltmc.loader.api.QuiltLoader;
17+
import org.quiltmc.loader.api.plugin.ModMetadataExt;
1518
import org.quiltmc.qsl.base.api.entrypoint.ModInitializer;
1619
import org.quiltmc.qsl.networking.api.ServerPlayNetworking;
1720

@@ -38,4 +41,8 @@ public void onInitialize(ModContainer mod) {
3841
public static ResourceLocation id(String path) {
3942
return new ResourceLocation(MOD_ID, path);
4043
}
44+
45+
public static String getIssuesURL() {
46+
return QuiltLoader.getModContainer(MOD_ID).map(ModContainer::metadata).map(meta -> meta.getContactInfo("issues")).orElse(MOD_ID);
47+
}
4148
}

src/main/java/dev/cammiescorner/camsbackpacks/client/screen/BackpackScreen.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import dev.cammiescorner.camsbackpacks.CamsBackpacks;
66
import dev.cammiescorner.camsbackpacks.client.CamsBackpacksClient;
77
import dev.cammiescorner.camsbackpacks.common.network.EquipBackpackPacket;
8-
import dev.cammiescorner.camsbackpacks.common.screen.BackpackScreenHandler;
8+
import dev.cammiescorner.camsbackpacks.common.menu.BackpackMenu;
99
import dev.cammiescorner.camsbackpacks.core.util.BackpackHelper;
1010
import net.minecraft.client.gui.GuiGraphics;
1111
import net.minecraft.client.gui.components.Button;
@@ -25,7 +25,7 @@
2525
import org.lwjgl.glfw.GLFW;
2626

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

40-
public BackpackScreen(BackpackScreenHandler screenHandler, Inventory playerInventory, Component text) {
40+
public BackpackScreen(BackpackMenu screenHandler, Inventory playerInventory, Component text) {
4141
super(screenHandler, playerInventory, text);
4242
this.playerInventory = playerInventory;
4343
this.imageWidth = 322;

src/main/java/dev/cammiescorner/camsbackpacks/common/blocks/entities/BackpackBlockEntity.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
package dev.cammiescorner.camsbackpacks.common.blocks.entities;
22

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

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

114114
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
package dev.cammiescorner.camsbackpacks.common.menu;
2+
3+
import dev.cammiescorner.camsbackpacks.CamsBackpacks;
4+
import dev.cammiescorner.camsbackpacks.common.menu.slot.ArmorSlot;
5+
import dev.cammiescorner.camsbackpacks.common.menu.slot.OffhandSlot;
6+
import dev.cammiescorner.camsbackpacks.core.mixin.accessor.CraftingMenuAccessor;
7+
import dev.cammiescorner.camsbackpacks.core.registry.ModScreenHandlers;
8+
import net.minecraft.core.BlockPos;
9+
import net.minecraft.core.NonNullList;
10+
import net.minecraft.nbt.CompoundTag;
11+
import net.minecraft.world.Container;
12+
import net.minecraft.world.ContainerHelper;
13+
import net.minecraft.world.SimpleContainer;
14+
import net.minecraft.world.entity.EquipmentSlot;
15+
import net.minecraft.world.entity.Mob;
16+
import net.minecraft.world.entity.player.Inventory;
17+
import net.minecraft.world.entity.player.Player;
18+
import net.minecraft.world.inventory.*;
19+
import net.minecraft.world.item.ItemStack;
20+
21+
import java.util.List;
22+
23+
public class BackpackMenu extends AbstractContainerMenu {
24+
25+
private static final List<EquipmentSlot> ARMOR_SLOTS = List.of(EquipmentSlot.FEET, EquipmentSlot.LEGS, EquipmentSlot.CHEST, EquipmentSlot.HEAD);
26+
27+
private final Player player;
28+
private final Container inventory;
29+
private final TransientCraftingContainer craftingInv;
30+
private final ResultContainer craftingResultInv;
31+
private final ContainerLevelAccess levelAccess;
32+
public final boolean isBlockEntity;
33+
public BlockPos blockPos;
34+
35+
public BackpackMenu(int syncId, Inventory playerInventory, BlockPos blockPos, boolean isBlockEntity) {
36+
this(syncId, playerInventory, new SimpleContainer(36), ContainerLevelAccess.NULL, blockPos, isBlockEntity);
37+
}
38+
39+
public BackpackMenu(int syncId, Inventory playerInventory, Container inventory, ContainerLevelAccess levelAccess, BlockPos blockPos, boolean isBlockEntity) {
40+
super(ModScreenHandlers.BACKPACK_SCREEN_HANDLER, syncId);
41+
checkContainerSize(inventory, 36);
42+
this.player = playerInventory.player;
43+
this.inventory = inventory;
44+
this.craftingInv = new TransientCraftingContainer(this, 3, 3);
45+
this.craftingResultInv = new ResultContainer();
46+
this.levelAccess = levelAccess;
47+
this.blockPos = blockPos;
48+
this.isBlockEntity = isBlockEntity;
49+
inventory.startOpen(player);
50+
51+
// Crafting result (slot 0) (global: 0)
52+
addSlot(new ResultSlot(player, craftingInv, craftingResultInv, 0, 273, 71 + 3 * 18));
53+
54+
// Crafting table inventory (slots 1-9) (global: 1-9)
55+
for (int y = 0; y < 3; ++y) {
56+
for (int x = 0; x < 3; ++x) {
57+
addSlot(new Slot(craftingInv, x + y * 3, 255 + x * 18, 46 + y * 18));
58+
}
59+
}
60+
61+
// Backpack inventory (slots 0-35) (global: 10-45)
62+
for (int y = 0; y < 4; ++y) {
63+
for (int x = 0; x < 9; ++x) {
64+
addSlot(new Slot(inventory, x + y * 9, 81 + x * 18, 18 + y * 18));
65+
}
66+
}
67+
68+
// Player inventory (slots 9-35) (global: 46-72)
69+
for (int y = 0; y < 3; ++y) {
70+
for (int x = 0; x < 9; ++x) {
71+
addSlot(new Slot(playerInventory, x + y * 9 + 9, 81 + x * 18, 108 + y * 18));
72+
}
73+
}
74+
75+
// Player hotbar (slots 0-8) (global: 73-82)
76+
for (int i = 0; i < 9; ++i) {
77+
addSlot(new Slot(playerInventory, i, 81 + i * 18, 166));
78+
}
79+
80+
// Player armor (slot 36-39) (global: 82-85)
81+
for (int i = 0; i < ARMOR_SLOTS.size(); ++i) {
82+
EquipmentSlot equipmentSlot = ARMOR_SLOTS.get(i);
83+
addSlot(new ArmorSlot(playerInventory, equipmentSlot.getIndex(36), 8, 105 - i * 18, equipmentSlot, player));
84+
}
85+
86+
// Player offhand (slot 40) (global: 86)
87+
this.addSlot(new OffhandSlot(playerInventory, 40, 8, 123, player));
88+
89+
}
90+
91+
@Override
92+
public void slotsChanged(Container inventory) {
93+
levelAccess.execute((world, pos) -> CraftingMenuAccessor.camsbackpacks$callSlotChangedCraftingGrid(this, world, player, craftingInv, craftingResultInv));
94+
}
95+
96+
@Override
97+
public ItemStack quickMoveStack(Player player, int index) {
98+
ItemStack newStack = ItemStack.EMPTY;
99+
Slot slot = this.slots.get(index);
100+
101+
if (slot.hasItem()) {
102+
ItemStack oldStack = slot.getItem();
103+
newStack = oldStack.copy();
104+
105+
if (index == 0) { // moving out of result slot (0) -> inv first, then backpack, then hotbar
106+
this.levelAccess.execute((world, pos) -> oldStack.getItem().onCraftedBy(oldStack, world, player));
107+
108+
// try player inv
109+
if (!moveItemStackTo(oldStack, 46, 73, false)) {
110+
111+
// try backpack inv
112+
if (!moveItemStackTo(oldStack, 10, 46, false)) {
113+
114+
// try hotbar
115+
if (!moveItemStackTo(oldStack, 73, 82, false)) {
116+
return ItemStack.EMPTY;
117+
}
118+
}
119+
}
120+
slot.onQuickCraft(oldStack, newStack);
121+
} else if (index <= 9) { // moving out of crafting inv (1-9) -> inv first, then backpack, then hotbar
122+
123+
// try player inv
124+
if (!moveItemStackTo(oldStack, 46, 73, false)) {
125+
126+
// try backpack inv
127+
if (!moveItemStackTo(oldStack, 10, 46, false)) {
128+
129+
// try hotbar
130+
if (!moveItemStackTo(oldStack, 73, 82, false)) {
131+
return ItemStack.EMPTY;
132+
}
133+
}
134+
}
135+
136+
} else if (index <= 45) { // moving out of backpack inv (10-45) -> armor inv, then hotbar, then regular inv
137+
138+
// try preferred armor slot
139+
EquipmentSlot equipmentSlot = Mob.getEquipmentSlotForItem(newStack);
140+
int armorSlotId = equipmentSlot.getIndex(82);
141+
if (equipmentSlot.getType() == EquipmentSlot.Type.ARMOR && !getSlot(armorSlotId).hasItem()) {
142+
if (!moveItemStackTo(oldStack, armorSlotId, armorSlotId + 1, false)) {
143+
144+
// try hotbar
145+
if (!moveItemStackTo(oldStack, 73, 82, false)) {
146+
147+
// try player inv
148+
if (!moveItemStackTo(oldStack, 46, 73, true)) {
149+
return ItemStack.EMPTY;
150+
}
151+
}
152+
}
153+
} else {
154+
155+
// try hotbar
156+
if (!moveItemStackTo(oldStack, 73, 82, false)) {
157+
158+
// try player inv
159+
if (!moveItemStackTo(oldStack, 46, 73, true)) {
160+
return ItemStack.EMPTY;
161+
}
162+
}
163+
}
164+
165+
} else if (index <= 72) { // moving out of player inv (46-72) -> backpack inv, then hotbar
166+
167+
// try backpack inv
168+
if (!moveItemStackTo(oldStack, 10, 46, false)) {
169+
170+
// try hotbar
171+
if (!moveItemStackTo(oldStack, 73, 82, true)) {
172+
return ItemStack.EMPTY;
173+
}
174+
}
175+
176+
} else if (index <= 81) { // moving out of hotbar (73-81) -> backpack inv, then player inv
177+
178+
// try backpack inv
179+
if (!moveItemStackTo(oldStack, 10, 46, false)) {
180+
181+
// try player inv
182+
if (!moveItemStackTo(oldStack, 46, 73, false)) {
183+
return ItemStack.EMPTY;
184+
}
185+
}
186+
187+
} else if (index <= 86) { // moving out of armor items (82-85) or offhand (86) -> backpack inv, then player inv, then hotbar
188+
189+
// try backpack inv
190+
if (!moveItemStackTo(oldStack, 10, 46, false)) {
191+
192+
// try player inv
193+
if (!moveItemStackTo(oldStack, 46, 73, false)) {
194+
195+
// try hotbar
196+
if (!moveItemStackTo(oldStack, 73, 82, true)) {
197+
return ItemStack.EMPTY;
198+
}
199+
}
200+
}
201+
202+
} else {
203+
// crash the game so we get bug reports
204+
throw new IllegalArgumentException("[Cammies-Wearable-Backpacks] Tried to quick transfer out of Slot [" + index + "]; please report this to " + CamsBackpacks.getIssuesURL());
205+
}
206+
207+
if (oldStack.isEmpty()) {
208+
slot.setByPlayer(ItemStack.EMPTY);
209+
} else {
210+
slot.setChanged();
211+
}
212+
213+
if (oldStack.getCount() == newStack.getCount()) {
214+
return ItemStack.EMPTY;
215+
}
216+
217+
slot.onTake(player, oldStack);
218+
219+
// can't put back into result slot, so drop remaining items
220+
if (index == 0) {
221+
player.drop(oldStack, false);
222+
}
223+
}
224+
225+
return newStack;
226+
}
227+
228+
@Override
229+
public void removed(Player player) {
230+
super.removed(player);
231+
levelAccess.execute((world, pos) -> {
232+
if (!world.isClientSide() && !isBlockEntity) {
233+
ItemStack stack = player.getItemBySlot(EquipmentSlot.CHEST);
234+
CompoundTag tag = stack.getOrCreateTag();
235+
NonNullList<ItemStack> inv = NonNullList.withSize(36, ItemStack.EMPTY);
236+
237+
for (int i = 0; i < inventory.getContainerSize(); i++)
238+
inv.set(i, inventory.getItem(i));
239+
240+
ContainerHelper.saveAllItems(tag, inv);
241+
}
242+
243+
clearContainer(player, craftingInv);
244+
});
245+
}
246+
247+
@Override
248+
public boolean stillValid(Player player) {
249+
return inventory.stillValid(player);
250+
}
251+
252+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package dev.cammiescorner.camsbackpacks.common.menu.slot;
2+
3+
import com.mojang.datafixers.util.Pair;
4+
import dev.cammiescorner.camsbackpacks.common.items.BackpackItem;
5+
import dev.cammiescorner.camsbackpacks.core.mixin.accessor.InventoryMenuAccessor;
6+
import net.minecraft.resources.ResourceLocation;
7+
import net.minecraft.world.entity.EquipmentSlot;
8+
import net.minecraft.world.entity.Mob;
9+
import net.minecraft.world.entity.player.Inventory;
10+
import net.minecraft.world.entity.player.Player;
11+
import net.minecraft.world.inventory.InventoryMenu;
12+
import net.minecraft.world.inventory.Slot;
13+
import net.minecraft.world.item.ItemStack;
14+
import net.minecraft.world.item.enchantment.EnchantmentHelper;
15+
16+
public class ArmorSlot extends Slot {
17+
18+
private final EquipmentSlot equipmentSlot;
19+
private final Player player;
20+
21+
public ArmorSlot(Inventory playerInventory, int slotIndex, int x, int y, EquipmentSlot equipmentSlot, Player player) {
22+
super(playerInventory, slotIndex, x, y);
23+
this.equipmentSlot = equipmentSlot;
24+
this.player = player;
25+
}
26+
27+
@Override
28+
public void setByPlayer(ItemStack stack) {
29+
InventoryMenuAccessor.camsbackpacks$callOnEquipItem(this.player, this.equipmentSlot, stack, this.getItem());
30+
super.setByPlayer(stack);
31+
}
32+
33+
@Override
34+
public int getMaxStackSize() {
35+
return 1;
36+
}
37+
38+
@Override
39+
public boolean mayPlace(ItemStack stack) {
40+
return equipmentSlot == Mob.getEquipmentSlotForItem(stack);
41+
}
42+
43+
@Override
44+
public boolean mayPickup(Player playerEntity) {
45+
ItemStack stack = getItem();
46+
return (stack.isEmpty() || playerEntity.isCreative() || !EnchantmentHelper.hasBindingCurse(stack)) && !(stack.getItem() instanceof BackpackItem) && super.mayPickup(playerEntity);
47+
}
48+
49+
@Override
50+
public Pair<ResourceLocation, ResourceLocation> getNoItemIcon() {
51+
return Pair.of(InventoryMenu.BLOCK_ATLAS, InventoryMenuAccessor.camsbackpacks$getEmptySlotsTextures()[equipmentSlot.getIndex()]);
52+
}
53+
}

0 commit comments

Comments
 (0)