diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8d26f015..168cc55e 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -3,7 +3,7 @@ name: OpenInv CI
on:
push:
branches:
- - '**'
+ - 'master'
tags-ignore:
- '**'
# Enable running CI via other Actions, i.e. for drafting releases and handling PRs.
@@ -41,3 +41,10 @@ jobs:
with:
name: api
path: ./api/target/openinvapi*.jar
+ - name: Build resource pack
+ id: upload-resource-pack
+ uses: actions/upload-artifact@v4
+ with:
+ name: openinv-legibility-pack
+ path: ./resource-pack/
+ compression-level: 9
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/PlayerDataManager.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/PlayerDataManager.java
index 87cd3627..4660d80a 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/PlayerDataManager.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/PlayerDataManager.java
@@ -20,9 +20,9 @@
import com.lishid.openinv.OpenInv;
import com.lishid.openinv.internal.IPlayerDataManager;
import com.lishid.openinv.internal.ISpecialInventory;
-import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.InventoryViewTitle;
import com.lishid.openinv.internal.OpenInventoryView;
+import com.lishid.openinv.internal.v1_21_R1.inventory.OpenInventory;
import com.mojang.authlib.GameProfile;
import com.mojang.serialization.Dynamic;
import net.minecraft.nbt.CompoundTag;
@@ -252,27 +252,50 @@ private void injectPlayer(ServerPlayer player) throws IllegalAccessException {
}
@Override
- public @Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) {
- if (inventory instanceof ISpecialPlayerInventory) {
- return player.openInventory(inventory.getBukkitInventory());
+ public @Nullable InventoryView openInventory(@NotNull Player bukkitPlayer, @NotNull ISpecialInventory inventory) {
+ ServerPlayer player = getHandle(bukkitPlayer);
+
+ if (player.connection == null) {
+ return null;
}
- ServerPlayer nmsPlayer = getHandle(player);
+ if (inventory instanceof OpenInventory container) {
+ // See net.minecraft.server.level.ServerPlayer#openMenu(MenuProvider)
+ AbstractContainerMenu menu = container.createMenu(player.nextContainerCounter(), player.getInventory(), player);
- if (nmsPlayer.connection == null) {
- return null;
+ // Should never happen, player is a ServerPlayer with an active connection.
+ if (menu == null) {
+ return null;
+ }
+
+ // Set up title (the whole reason we're not just using Player#openInventory(Inventory)).
+ // Title can only be set once for a menu, and is set during the open process.
+ menu.setTitle(container.getTitle(player));
+
+ menu = CraftEventFactory.callInventoryOpenEvent(player, menu, false);
+
+ // Menu is null if event is cancelled.
+ if (menu == null) {
+ return null;
+ }
+
+ player.containerMenu = menu;
+ player.connection.send(new ClientboundOpenScreenPacket(menu.containerId, menu.getType(), menu.getTitle()));
+ player.initMenu(menu);
+
+ return menu.getBukkitView();
}
InventoryViewTitle viewTitle = InventoryViewTitle.of(inventory);
if (viewTitle == null) {
- return player.openInventory(inventory.getBukkitInventory());
+ return bukkitPlayer.openInventory(inventory.getBukkitInventory());
}
- String originalTitle = viewTitle.getTitle(player, inventory);
- InventoryView view = viewProvider.apply(player, inventory, originalTitle);
+ String originalTitle = viewTitle.getTitle(bukkitPlayer, inventory);
+ InventoryView view = viewProvider.apply(bukkitPlayer, inventory, originalTitle);
Component title = Component.literal(originalTitle);
- AbstractContainerMenu container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) {
+ AbstractContainerMenu container = new CraftContainer(view, player, player.nextContainerCounter()) {
@Override
public MenuType> getType() {
return getContainers(inventory.getBukkitInventory().getSize());
@@ -280,7 +303,7 @@ public MenuType> getType() {
};
container.setTitle(title);
- container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container);
+ container = CraftEventFactory.callInventoryOpenEvent(player, container);
if (container == null) {
return null;
@@ -289,9 +312,9 @@ public MenuType> getType() {
// Note: Reusing component prevents plugins from changing title during InventoryOpenEvent, but there's not much
// we can do about that - we can't call InventoryView#getTitle on older versions without causing an
// IncompatibleClassChangeError due to the fact that InventoryView is now an interface.
- nmsPlayer.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), title));
- nmsPlayer.containerMenu = container;
- nmsPlayer.initMenu(container);
+ player.connection.send(new ClientboundOpenScreenPacket(container.containerId, container.getType(), title));
+ player.containerMenu = container;
+ player.initMenu(container);
return container.getBukkitView();
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCrafting.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCrafting.java
index 02462dce..f3f241cf 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCrafting.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCrafting.java
@@ -102,7 +102,7 @@ private SlotCrafting(Container container, int index, int x, int y) {
@Override
ItemStack getOrDefault() {
- return isAvailable() ? items.get(ContainerSlotCrafting.this.index) : survivalOnly(holder);
+ return isAvailable() ? items.get(ContainerSlotCrafting.this.index) : PlaceholderManager.survivalOnly(holder);
}
@Override
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCraftingResult.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCraftingResult.java
index b43b3185..55a8224b 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCraftingResult.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCraftingResult.java
@@ -13,7 +13,7 @@
*
*
Unmodifiable because I said so. Use your own crafting grid.
*/
-class ContainerSlotCraftingResult extends ContainerSlotEmpty {
+class ContainerSlotCraftingResult extends ContainerSlotUninteractable {
ContainerSlotCraftingResult(@NotNull ServerPlayer holder) {
super(holder);
@@ -27,11 +27,11 @@ public ItemStack get() {
@Override
public Slot asMenuSlot(Container container, int index, int x, int y) {
- return new ContainerSlotEmpty.SlotEmpty(container, index, x, y) {
+ return new ContainerSlotUninteractable.SlotEmpty(container, index, x, y) {
@Override
ItemStack getOrDefault() {
if (!ContainerSlotCrafting.isAvailable(holder)) {
- return survivalOnly(holder);
+ return PlaceholderManager.survivalOnly(holder);
}
InventoryMenu inventoryMenu = holder.inventoryMenu;
return inventoryMenu.getSlot(inventoryMenu.getResultSlotIndex()).getItem();
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCursor.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCursor.java
index f570fa08..65a9e33c 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCursor.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotCursor.java
@@ -1,48 +1,18 @@
package com.lishid.openinv.internal.v1_21_R1.inventory;
-import net.minecraft.core.Registry;
-import net.minecraft.core.RegistryAccess;
-import net.minecraft.core.component.DataComponents;
-import net.minecraft.core.registries.Registries;
import net.minecraft.server.level.ServerPlayer;
-import net.minecraft.util.Unit;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
-import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
-import net.minecraft.world.level.block.entity.BannerPattern;
-import net.minecraft.world.level.block.entity.BannerPatternLayers;
-import net.minecraft.world.level.block.entity.BannerPatterns;
-import org.bukkit.craftbukkit.v1_21_R1.CraftRegistry;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
-import java.util.List;
-
/**
* A slot wrapping the active menu's cursor. Unavailable when not online in a survival mode.
*/
class ContainerSlotCursor implements ContainerSlot {
- private static final ItemStack PLACEHOLDER;
-
- static {
- PLACEHOLDER = new ItemStack(Items.WHITE_BANNER);
- RegistryAccess minecraftRegistry = CraftRegistry.getMinecraftRegistry();
- Registry bannerPatterns = minecraftRegistry.registryOrThrow(Registries.BANNER_PATTERN);
- BannerPattern halfDiagBottomRight = bannerPatterns.getOrThrow(BannerPatterns.DIAGONAL_RIGHT);
- BannerPattern downRight = bannerPatterns.getOrThrow(BannerPatterns.STRIPE_DOWNRIGHT);
- BannerPattern border = bannerPatterns.getOrThrow(BannerPatterns.BORDER);
- PLACEHOLDER.set(DataComponents.BANNER_PATTERNS,
- new BannerPatternLayers(List.of(
- new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(halfDiagBottomRight), DyeColor.GRAY),
- new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(downRight), DyeColor.WHITE),
- new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(border), DyeColor.GRAY))));
- PLACEHOLDER.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
- }
-
private @NotNull ServerPlayer holder;
ContainerSlotCursor(@NotNull ServerPlayer holder) {
@@ -115,10 +85,10 @@ private SlotCursor(Container container, int index, int x, int y) {
@Override
ItemStack getOrDefault() {
if (!isAvailable()) {
- return survivalOnly(holder);
+ return PlaceholderManager.survivalOnly(holder);
}
ItemStack carried = holder.containerMenu.getCarried();
- return carried.isEmpty() ? PLACEHOLDER : carried;
+ return carried.isEmpty() ? PlaceholderManager.cursor : carried;
}
@Override
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotDrop.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotDrop.java
index f2d41e58..355ccd1f 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotDrop.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotDrop.java
@@ -1,12 +1,9 @@
package com.lishid.openinv.internal.v1_21_R1.inventory;
-import net.minecraft.core.component.DataComponents;
-import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
@@ -15,15 +12,8 @@
*/
class ContainerSlotDrop implements ContainerSlot {
- private static final ItemStack DROP;
private ServerPlayer holder;
- static {
- DROP = new ItemStack(Items.DROPPER);
- // Note: translatable component, not keybind component! We want the text identifying the keybind, not the key.
- DROP.set(DataComponents.CUSTOM_NAME, Component.translatable("key.drop").withStyle(style -> style.withItalic(false)));
- }
-
ContainerSlotDrop(@NotNull ServerPlayer holder) {
this.holder = holder;
}
@@ -72,7 +62,9 @@ private SlotDrop(Container container, int index, int x, int y) {
@Override
ItemStack getOrDefault() {
- return holder.connection != null && !holder.connection.isDisconnected() ? DROP : OFFLINE;
+ return holder.connection != null && !holder.connection.isDisconnected()
+ ? PlaceholderManager.drop
+ : PlaceholderManager.blockedOffline;
}
@Override
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotEquipment.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotEquipment.java
index 57646fb7..0d6cfa19 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotEquipment.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotEquipment.java
@@ -1,87 +1,29 @@
package com.lishid.openinv.internal.v1_21_R1.inventory;
-import net.minecraft.core.Registry;
-import net.minecraft.core.RegistryAccess;
-import net.minecraft.core.component.DataComponents;
-import net.minecraft.core.registries.Registries;
import net.minecraft.server.level.ServerPlayer;
-import net.minecraft.util.Unit;
import net.minecraft.world.Container;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.inventory.Slot;
-import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
-import net.minecraft.world.item.component.DyedItemColor;
-import net.minecraft.world.level.block.entity.BannerPattern;
-import net.minecraft.world.level.block.entity.BannerPatternLayers;
-import net.minecraft.world.level.block.entity.BannerPatterns;
-import org.bukkit.craftbukkit.v1_21_R1.CraftRegistry;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
-import java.util.List;
-
/**
* A slot for equipment that displays placeholders if empty.
*/
class ContainerSlotEquipment extends ContainerSlotList {
- private static final ItemStack HELMET;
- private static final ItemStack CHESTPLATE;
- private static final ItemStack LEGGINGS;
- private static final ItemStack BOOTS;
- private static final ItemStack SHIELD;
-
- static {
- HELMET = new ItemStack(Items.LEATHER_HELMET);
- // Inventory-background-grey-ish
- DyedItemColor color = new DyedItemColor(0xC8C8C8, false);
- HELMET.set(DataComponents.DYED_COLOR, color);
- HELMET.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
-
- CHESTPLATE = new ItemStack(Items.LEATHER_CHESTPLATE);
- CHESTPLATE.set(DataComponents.DYED_COLOR, color);
- CHESTPLATE.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
-
- LEGGINGS = new ItemStack(Items.LEATHER_LEGGINGS);
- LEGGINGS.set(DataComponents.DYED_COLOR, color);
- LEGGINGS.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
-
- BOOTS = new ItemStack(Items.LEATHER_BOOTS);
- BOOTS.set(DataComponents.DYED_COLOR, color);
- BOOTS.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
-
- SHIELD = new ItemStack(Items.SHIELD);
- SHIELD.set(DataComponents.BASE_COLOR, DyeColor.MAGENTA);
- RegistryAccess minecraftRegistry = CraftRegistry.getMinecraftRegistry();
- Registry bannerPatterns = minecraftRegistry.registryOrThrow(Registries.BANNER_PATTERN);
- BannerPattern halfLeft = bannerPatterns.getOrThrow(BannerPatterns.HALF_VERTICAL);
- BannerPattern topLeft = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_TOP_LEFT);
- BannerPattern topRight = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_TOP_RIGHT);
- BannerPattern bottomLeft = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_BOTTOM_LEFT);
- BannerPattern bottomRight = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_BOTTOM_RIGHT);
- SHIELD.set(DataComponents.BANNER_PATTERNS,
- new BannerPatternLayers(List.of(
- new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(halfLeft), DyeColor.BLACK),
- new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(topLeft), DyeColor.MAGENTA),
- new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(bottomLeft), DyeColor.MAGENTA),
- new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(topRight), DyeColor.BLACK),
- new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(bottomRight), DyeColor.BLACK))));
- SHIELD.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
- }
-
private final ItemStack placeholder;
private final EquipmentSlot equipmentSlot;
ContainerSlotEquipment(ServerPlayer holder, int index, EquipmentSlot equipmentSlot) {
super(holder, index, InventoryType.SlotType.ARMOR);
placeholder = switch (equipmentSlot) {
- case HEAD -> HELMET;
- case CHEST -> CHESTPLATE;
- case LEGS -> LEGGINGS;
- case FEET -> BOOTS;
- default -> SHIELD;
+ case HEAD -> PlaceholderManager.emptyHelmet;
+ case CHEST -> PlaceholderManager.emptyChestplate;
+ case LEGS -> PlaceholderManager.emptyLeggings;
+ case FEET -> PlaceholderManager.emptyBoots;
+ default -> PlaceholderManager.emptyOffHand;
};
this.equipmentSlot = equipmentSlot;
}
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotEmpty.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotUninteractable.java
similarity index 85%
rename from internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotEmpty.java
rename to internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotUninteractable.java
index 265999b3..57b1e53b 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotEmpty.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/ContainerSlotUninteractable.java
@@ -1,33 +1,23 @@
package com.lishid.openinv.internal.v1_21_R1.inventory;
-import net.minecraft.core.component.DataComponents;
import net.minecraft.server.level.ServerPlayer;
-import net.minecraft.util.Unit;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
/**
- * A fake slot used to fill unused spaces in the inventory.
+ * A fake slot used to fill spaces in the inventory that can't be interacted with.
*/
-class ContainerSlotEmpty implements ContainerSlot {
-
- private static final ItemStack PLACEHOLDER;
-
- static {
- PLACEHOLDER = new ItemStack(Items.WHITE_STAINED_GLASS_PANE);
- PLACEHOLDER.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
- }
+class ContainerSlotUninteractable implements ContainerSlot {
@NotNull ServerPlayer holder;
- ContainerSlotEmpty(@NotNull ServerPlayer holder) {
+ ContainerSlotUninteractable(@NotNull ServerPlayer holder) {
this.holder = holder;
}
@@ -74,7 +64,7 @@ static class SlotEmpty extends MenuSlotPlaceholder {
@Override
ItemStack getOrDefault() {
- return PLACEHOLDER;
+ return PlaceholderManager.notSlot;
}
public void onQuickCraft(ItemStack var0, ItemStack var1) {}
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/MenuSlotPlaceholder.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/MenuSlotPlaceholder.java
index 898c6086..b29afdc5 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/MenuSlotPlaceholder.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/MenuSlotPlaceholder.java
@@ -1,14 +1,8 @@
package com.lishid.openinv.internal.v1_21_R1.inventory;
-import net.minecraft.core.component.DataComponents;
-import net.minecraft.network.chat.Component;
-import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
-import net.minecraft.world.level.GameType;
-import org.jetbrains.annotations.NotNull;
/**
* An implementation of a slot as used by a menu that may have fake placeholder items.
@@ -17,60 +11,6 @@
*/
abstract class MenuSlotPlaceholder extends Slot {
- static final ItemStack OFFLINE;
- private static final ItemStack CREATIVE;
- private static final ItemStack SPECTATOR;
-
- static {
- // Barrier: "Not available - Offline"
- OFFLINE = new ItemStack(Items.BARRIER);
- OFFLINE.set(DataComponents.CUSTOM_NAME,
- Component.translatable("options.narrator.notavailable")
- .withStyle(style -> style.withItalic(false))
- .append(Component.literal(" - "))
- .append(Component.translatable("gui.socialInteractions.status_offline")));
- // Barrier: "Not available - Creative Mode"
- CREATIVE = new ItemStack(Items.BARRIER);
- CREATIVE.set(
- DataComponents.CUSTOM_NAME,
- Component.translatable("options.narrator.notavailable")
- .withStyle(style -> style.withItalic(false))
- .append(" - ")
- .append(GameType.CREATIVE.getLongDisplayName()));
- // Barrier: "Not available - Spectator Mode"
- SPECTATOR = new ItemStack(Items.BARRIER);
- SPECTATOR.set(
- DataComponents.CUSTOM_NAME,
- Component.translatable("options.narrator.notavailable")
- .withStyle(style -> style.withItalic(false))
- .append(" - ")
- .append(GameType.SPECTATOR.getLongDisplayName()));
- }
-
- public static ItemStack survivalOnly(@NotNull ServerPlayer serverPlayer) {
- if (serverPlayer.connection == null || serverPlayer.connection.isDisconnected()) {
- return OFFLINE;
- }
-
- GameType gameType = serverPlayer.gameMode.getGameModeForPlayer();
- return switch (gameType) {
- case CREATIVE -> CREATIVE;
- case SPECTATOR -> SPECTATOR;
- // Just in case, fall through to creating new items.
- // This is a lot less good - inventory syncher will create copies frequently.
- default -> {
- ItemStack itemStack = new ItemStack(Items.BARRIER);
- itemStack.set(
- DataComponents.CUSTOM_NAME,
- Component.translatable("options.narrator.notavailable")
- .withStyle(style -> style.withItalic(false))
- .append(" - ")
- .append(gameType.getLongDisplayName()));
- yield itemStack;
- }
- };
- }
-
MenuSlotPlaceholder(Container container, int index, int x, int y) {
super(container, index, x, y);
}
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/OpenInventory.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/OpenInventory.java
index a96513ac..9d6e438f 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/OpenInventory.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/OpenInventory.java
@@ -2,9 +2,11 @@
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.v1_21_R1.PlayerDataManager;
+import net.minecraft.ChatFormatting;
import net.minecraft.core.NonNullList;
-import net.minecraft.core.component.DataComponents;
import net.minecraft.network.chat.Component;
+import net.minecraft.network.chat.MutableComponent;
+import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.MenuProvider;
@@ -15,7 +17,6 @@
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.Slot;
import net.minecraft.world.item.ItemStack;
-import net.minecraft.world.item.Items;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_21_R1.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftInventory;
@@ -43,7 +44,7 @@ public OpenInventory(@NotNull org.bukkit.entity.Player bukkitPlayer) {
int rawSize = owner.getInventory().getContainerSize() + owner.inventoryMenu.getCraftSlots().getContainerSize() + 1;
size = ((int) Math.ceil(rawSize / 9.0)) * 9;
- slots = NonNullList.withSize(size, new ContainerSlotEmpty(owner));
+ slots = NonNullList.withSize(size, new ContainerSlotUninteractable(owner));
setupSlots();
}
@@ -168,18 +169,13 @@ private int addCrafting(int startIndex, boolean pretty) {
}
if (pretty) {
- slots.set(startIndex + 2, new ContainerSlotEmpty(owner) {
- private static final ItemStack PLACEHOLDER = new ItemStack(Items.CRAFTING_TABLE);
- static {
- PLACEHOLDER.set(DataComponents.CUSTOM_NAME, Component.translatable("container.crafting").withStyle(style -> style.withItalic(false)));
- }
-
+ slots.set(startIndex + 2, new ContainerSlotUninteractable(owner) {
@Override
public Slot asMenuSlot(Container container, int index, int x, int y) {
- return new ContainerSlotEmpty.SlotEmpty(container, index, x, y) {
+ return new ContainerSlotUninteractable.SlotEmpty(container, index, x, y) {
@Override
ItemStack getOrDefault() {
- return PLACEHOLDER;
+ return PlaceholderManager.craftingOutput;
}
};
}
@@ -202,6 +198,28 @@ public ServerPlayer getOwnerHandle() {
return owner;
}
+ public @NotNull Component getTitle(@Nullable ServerPlayer viewer) {
+ MutableComponent component = Component.empty();
+ // Prefix for use with custom bitmap image fonts.
+ if (viewer == owner) {
+ component.append(
+ Component.translatableWithFallback("openinv.container.inventory.self", "")
+ .withStyle(style -> style
+ .withFont(ResourceLocation.parse("openinv:font/inventory"))
+ .withColor(ChatFormatting.WHITE)));
+ } else {
+ component.append(
+ Component.translatableWithFallback("openinv.container.inventory.other", "")
+ .withStyle(style -> style
+ .withFont(ResourceLocation.parse("openinv:font/inventory"))
+ .withColor(ChatFormatting.WHITE)));
+ }
+ // Normal title: "Inventory - OwnerName"
+ component.append(Component.translatable("container.inventory"))
+ .append(Component.translatableWithFallback("openinv.container.inventory.suffix", " - %s", owner.getName()));
+ return component;
+ }
+
@Override
public @NotNull org.bukkit.inventory.Inventory getBukkitInventory() {
if (bukkitEntity == null) {
@@ -320,7 +338,7 @@ public void clearContent() {
@Override
public Component getName() {
- return Component.translatable("key.categories.inventory").append(" - ").append(owner.getName());
+ return getTitle(null);
}
@Override
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/OpenInventoryMenu.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/OpenInventoryMenu.java
index e7e70afd..54b194da 100644
--- a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/OpenInventoryMenu.java
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/OpenInventoryMenu.java
@@ -59,7 +59,7 @@ protected OpenInventoryMenu(OpenInventory inventory, ServerPlayer viewer, int i)
// Guard against weird inventory sizes.
if (index >= inventory.getContainerSize()) {
- addSlot(new ContainerSlotEmpty.SlotEmpty(inventory, index, x, y));
+ addSlot(new ContainerSlotUninteractable.SlotEmpty(inventory, index, x, y));
continue;
}
@@ -67,7 +67,7 @@ protected OpenInventoryMenu(OpenInventory inventory, ServerPlayer viewer, int i)
// Only allow access to own gear slots and drop slot (though really, just click outside the inventory).
if (ownInv && !(slot instanceof ContainerSlotEquipment.SlotEquipment || slot instanceof ContainerSlotDrop.SlotDrop)) {
- slot = new ContainerSlotEmpty.SlotEmpty(inventory, index, x, y);
+ slot = new ContainerSlotUninteractable.SlotEmpty(inventory, index, x, y);
}
addSlot(slot);
}
@@ -465,7 +465,7 @@ private static boolean addToExistingStack(ItemStack itemStack, Slot slot) {
@Override
public boolean canDragTo(Slot slot) {
- return !(slot instanceof ContainerSlotDrop.SlotDrop || slot instanceof ContainerSlotEmpty.SlotEmpty);
+ return !(slot instanceof ContainerSlotDrop.SlotDrop || slot instanceof ContainerSlotUninteractable.SlotEmpty);
}
}
diff --git a/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/PlaceholderManager.java b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/PlaceholderManager.java
new file mode 100644
index 00000000..9a594460
--- /dev/null
+++ b/internal/v1_21_R1/src/main/java/com/lishid/openinv/internal/v1_21_R1/inventory/PlaceholderManager.java
@@ -0,0 +1,181 @@
+package com.lishid.openinv.internal.v1_21_R1.inventory;
+
+import com.lishid.openinv.internal.PlaceholderParser;
+import net.minecraft.core.Registry;
+import net.minecraft.core.RegistryAccess;
+import net.minecraft.core.component.DataComponents;
+import net.minecraft.core.registries.Registries;
+import net.minecraft.nbt.CompoundTag;
+import net.minecraft.nbt.TagParser;
+import net.minecraft.network.chat.Component;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.util.Unit;
+import net.minecraft.world.item.DyeColor;
+import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.item.Items;
+import net.minecraft.world.item.component.CustomModelData;
+import net.minecraft.world.item.component.DyedItemColor;
+import net.minecraft.world.level.GameType;
+import net.minecraft.world.level.ItemLike;
+import net.minecraft.world.level.block.entity.BannerPattern;
+import net.minecraft.world.level.block.entity.BannerPatternLayers;
+import net.minecraft.world.level.block.entity.BannerPatterns;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.craftbukkit.v1_21_R1.CraftRegistry;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.EnumMap;
+import java.util.List;
+import java.util.Optional;
+
+public class PlaceholderManager implements PlaceholderParser {
+
+ private static final CustomModelData DEFAULT_CUSTOM_MODEL_DATA = new CustomModelData(9999);
+ static final @NotNull EnumMap BLOCKED_GAME_TYPE = new EnumMap<>(GameType.class);
+ static @NotNull ItemStack craftingOutput = defaultCraftingOutput();
+ static @NotNull ItemStack cursor = defaultCursor();
+ static @NotNull ItemStack drop = defaultDrop();
+ static @NotNull ItemStack emptyHelmet = getEmptyArmor(Items.LEATHER_HELMET);
+ static @NotNull ItemStack emptyChestplate = getEmptyArmor(Items.LEATHER_CHESTPLATE);
+ static @NotNull ItemStack emptyLeggings = getEmptyArmor(Items.LEATHER_LEGGINGS);
+ static @NotNull ItemStack emptyBoots = getEmptyArmor(Items.LEATHER_BOOTS);
+ static @NotNull ItemStack emptyOffHand = getEmptyShield();
+ static @NotNull ItemStack notSlot = defaultNotSlot();
+ static @NotNull ItemStack blockedOffline = defaultBlockedOffline();
+
+ static {
+ for (GameType type : GameType.values()) {
+ // Barrier: "Not available - Creative" etc.
+ ItemStack typeItem = new ItemStack(Items.BARRIER);
+ typeItem.set(
+ DataComponents.ITEM_NAME,
+ Component.translatable("options.narrator.notavailable").append(" - ").append(type.getShortDisplayName()));
+ BLOCKED_GAME_TYPE.put(type, typeItem);
+ }
+ }
+
+ @Override
+ public void load(@NotNull ConfigurationSection section) throws Exception {
+ craftingOutput = parse(section, "crafting-output", craftingOutput);
+ cursor = parse(section, "cursor", cursor);
+ drop = parse(section, "drop", drop);
+ emptyHelmet = parse(section, "empty-helmet", emptyHelmet);
+ emptyChestplate = parse(section, "empty-chestplate", emptyChestplate);
+ emptyLeggings = parse(section, "empty-leggings", emptyLeggings);
+ emptyBoots = parse(section, "empty-boots", emptyBoots);
+ emptyOffHand = parse(section, "empty-off-hand", emptyOffHand);
+ notSlot = parse(section, "not-a-slot", notSlot);
+ blockedOffline = parse(section, "blocked.offline", blockedOffline);
+ BLOCKED_GAME_TYPE.put(GameType.CREATIVE, parse(section, "blocked.creative", BLOCKED_GAME_TYPE.get(GameType.CREATIVE)));
+ BLOCKED_GAME_TYPE.put(GameType.SPECTATOR, parse(section, "blocked.spectator", BLOCKED_GAME_TYPE.get(GameType.SPECTATOR)));
+ }
+
+ private @NotNull ItemStack parse(
+ @NotNull ConfigurationSection section,
+ @NotNull String path,
+ @NotNull ItemStack defaultStack) throws Exception {
+ String itemText = section.getString(path);
+
+ if (itemText == null) {
+ return defaultStack;
+ }
+
+ CompoundTag compoundTag = TagParser.parseTag(itemText);
+ Optional parsed = ItemStack.parse(CraftRegistry.getMinecraftRegistry(), compoundTag);
+ return parsed.filter(itemStack -> !itemStack.isEmpty()).orElse(defaultStack);
+ }
+
+ static ItemStack survivalOnly(@NotNull ServerPlayer serverPlayer) {
+ if (serverPlayer.connection == null || serverPlayer.connection.isDisconnected()) {
+ return blockedOffline;
+ }
+
+ return BLOCKED_GAME_TYPE.getOrDefault(serverPlayer.gameMode.getGameModeForPlayer(), ItemStack.EMPTY);
+ }
+
+ private static ItemStack defaultCraftingOutput() {
+ // Crafting table: "Crafting"
+ ItemStack itemStack = new ItemStack(Items.CRAFTING_TABLE);
+ itemStack.set(DataComponents.ITEM_NAME, Component.translatable("container.crafting"));
+ itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
+ return itemStack;
+ }
+
+ private static ItemStack defaultCursor() {
+ // Cursor-like banner with no tooltip
+ ItemStack itemStack = new ItemStack(Items.WHITE_BANNER);
+ RegistryAccess minecraftRegistry = CraftRegistry.getMinecraftRegistry();
+ Registry bannerPatterns = minecraftRegistry.registryOrThrow(Registries.BANNER_PATTERN);
+ BannerPattern halfDiagBottomRight = bannerPatterns.getOrThrow(BannerPatterns.DIAGONAL_RIGHT);
+ BannerPattern downRight = bannerPatterns.getOrThrow(BannerPatterns.STRIPE_DOWNRIGHT);
+ BannerPattern border = bannerPatterns.getOrThrow(BannerPatterns.BORDER);
+ itemStack.set(DataComponents.BANNER_PATTERNS,
+ new BannerPatternLayers(List.of(
+ new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(halfDiagBottomRight), DyeColor.GRAY),
+ new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(downRight), DyeColor.WHITE),
+ new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(border), DyeColor.GRAY))));
+ itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
+ itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
+ return itemStack;
+ }
+
+ private static ItemStack defaultDrop() {
+ // Dropper: "Drop Selected Item"
+ ItemStack itemStack = new ItemStack(Items.DROPPER);
+ // Note: translatable component, not keybind component! We want the text identifying the keybind, not the key.
+ itemStack.set(DataComponents.ITEM_NAME, Component.translatable("key.drop"));
+ itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
+ return itemStack;
+ }
+
+ private static ItemStack getEmptyArmor(ItemLike item) {
+ // Inventory-background-grey-ish leather armor with no tooltip
+ ItemStack itemStack = new ItemStack(item);
+ DyedItemColor color = new DyedItemColor(0xC8C8C8, false);
+ itemStack.set(DataComponents.DYED_COLOR, color);
+ itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
+ itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
+ return itemStack;
+ }
+
+ private static ItemStack getEmptyShield() {
+ ItemStack itemStack = new ItemStack(Items.SHIELD);
+ itemStack.set(DataComponents.BASE_COLOR, DyeColor.MAGENTA);
+ RegistryAccess minecraftRegistry = CraftRegistry.getMinecraftRegistry();
+ Registry bannerPatterns = minecraftRegistry.registryOrThrow(Registries.BANNER_PATTERN);
+ BannerPattern halfLeft = bannerPatterns.getOrThrow(BannerPatterns.HALF_VERTICAL);
+ BannerPattern topLeft = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_TOP_LEFT);
+ BannerPattern topRight = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_TOP_RIGHT);
+ BannerPattern bottomLeft = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_BOTTOM_LEFT);
+ BannerPattern bottomRight = bannerPatterns.getOrThrow(BannerPatterns.SQUARE_BOTTOM_RIGHT);
+ itemStack.set(DataComponents.BANNER_PATTERNS,
+ new BannerPatternLayers(List.of(
+ new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(halfLeft), DyeColor.BLACK),
+ new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(topLeft), DyeColor.MAGENTA),
+ new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(bottomLeft), DyeColor.MAGENTA),
+ new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(topRight), DyeColor.BLACK),
+ new BannerPatternLayers.Layer(bannerPatterns.wrapAsHolder(bottomRight), DyeColor.BLACK))));
+ itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
+ itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
+ return itemStack;
+ }
+
+ private static ItemStack defaultNotSlot() {
+ // White pane with no tooltip
+ ItemStack itemStack = new ItemStack(Items.WHITE_STAINED_GLASS_PANE);
+ itemStack.set(DataComponents.HIDE_TOOLTIP, Unit.INSTANCE);
+ itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
+ return itemStack;
+ }
+
+ private static ItemStack defaultBlockedOffline() {
+ // Barrier: "Not available - Offline"
+ ItemStack itemStack = new ItemStack(Items.BARRIER);
+ itemStack.set(DataComponents.ITEM_NAME,
+ Component.translatable("options.narrator.notavailable")
+ .append(Component.literal(" - "))
+ .append(Component.translatable("gui.socialInteractions.status_offline")));
+ return itemStack;
+ }
+
+}
diff --git a/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java b/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java
index c01c6abb..63c2a067 100644
--- a/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java
+++ b/plugin/src/main/java/com/lishid/openinv/InternalAccessor.java
@@ -23,13 +23,16 @@
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
+import com.lishid.openinv.internal.PlaceholderParser;
import com.lishid.openinv.util.InventoryAccess;
+import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Constructor;
+import java.util.logging.Level;
class InternalAccessor {
@@ -38,6 +41,7 @@ class InternalAccessor {
private boolean supported = false;
private IPlayerDataManager playerDataManager;
private IAnySilentContainer anySilentContainer;
+ private @Nullable PlaceholderParser placeholderParser;
InternalAccessor(@NotNull Plugin plugin) {
this.plugin = plugin;
@@ -52,6 +56,7 @@ private void checkSupported() {
try {
try {
Class.forName("com.lishid.openinv.internal." + this.versionPackage + ".inventory.OpenInventory");
+ this.placeholderParser = createObject(PlaceholderParser.class, "inventory.PlaceholderManager");
} catch (ClassNotFoundException e) {
Class.forName("com.lishid.openinv.internal." + this.versionPackage + ".SpecialPlayerInventory");
}
@@ -233,6 +238,24 @@ public String getReleasesLink() {
return this.playerDataManager;
}
+ /**
+ * Reload internal features.
+ */
+ void reload() {
+ if (placeholderParser == null) {
+ return;
+ }
+
+ ConfigurationSection placeholders = plugin.getConfig().getConfigurationSection("placeholders");
+ if (placeholders != null) {
+ try {
+ placeholderParser.load(placeholders);
+ } catch (Exception e) {
+ plugin.getLogger().log(Level.WARNING, "Caught exception loading placeholder overrides!", e);
+ }
+ }
+ }
+
/**
* Gets the server implementation version.
*
diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java
index 38bea972..a42f2adf 100644
--- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java
+++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java
@@ -86,6 +86,9 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
public void reloadConfig() {
super.reloadConfig();
this.offlineHandler = disableOfflineAccess() ? OfflineHandler.REMOVE_AND_CLOSE : OfflineHandler.REQUIRE_PERMISSIONS;
+ if (this.accessor != null && this.accessor.isSupported()) {
+ this.accessor.reload();
+ }
}
@Override
@@ -133,7 +136,6 @@ public void onEnable() {
this.accessor = new InternalAccessor(this);
this.languageManager = new LanguageManager(this, "en_us");
- this.offlineHandler = disableOfflineAccess() ? OfflineHandler.REMOVE_AND_CLOSE : OfflineHandler.REQUIRE_PERMISSIONS;
try {
Class.forName("org.bukkit.entity.Player$Spigot");
@@ -144,6 +146,8 @@ public void onEnable() {
// Version check
if (isSpigot && this.accessor.isSupported()) {
+ reloadConfig();
+
// Update existing configuration. May require internal access.
new ConfigUpdater(this).checkForUpdates();
diff --git a/plugin/src/main/java/com/lishid/openinv/internal/PlaceholderParser.java b/plugin/src/main/java/com/lishid/openinv/internal/PlaceholderParser.java
new file mode 100644
index 00000000..05a8c17b
--- /dev/null
+++ b/plugin/src/main/java/com/lishid/openinv/internal/PlaceholderParser.java
@@ -0,0 +1,9 @@
+package com.lishid.openinv.internal;
+
+import org.bukkit.configuration.ConfigurationSection;
+
+public interface PlaceholderParser {
+
+ void load(ConfigurationSection section) throws Exception;
+
+}
diff --git a/resource-pack/assets/minecraft/models/item/crafting_table.json b/resource-pack/assets/minecraft/models/item/crafting_table.json
new file mode 100644
index 00000000..230469c5
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/crafting_table.json
@@ -0,0 +1,11 @@
+{
+ "parent": "minecraft:block/crafting_table",
+ "overrides": [
+ {
+ "model": "openinv:item/crafting_output",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ }
+ ]
+}
diff --git a/resource-pack/assets/minecraft/models/item/dropper.json b/resource-pack/assets/minecraft/models/item/dropper.json
new file mode 100644
index 00000000..0c8bb744
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/dropper.json
@@ -0,0 +1,11 @@
+{
+ "parent": "minecraft:block/dropper",
+ "overrides": [
+ {
+ "model": "openinv:item/drop",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ }
+ ]
+}
diff --git a/resource-pack/assets/minecraft/models/item/leather_boots.json b/resource-pack/assets/minecraft/models/item/leather_boots.json
new file mode 100644
index 00000000..f9cd4073
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/leather_boots.json
@@ -0,0 +1,75 @@
+{
+ "parent": "minecraft:item/generated",
+ "overrides": [
+ {
+ "model": "openinv:item/empty_boots",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_quartz_trim",
+ "predicate": {
+ "trim_type": 0.1
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_iron_trim",
+ "predicate": {
+ "trim_type": 0.2
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_netherite_trim",
+ "predicate": {
+ "trim_type": 0.3
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_redstone_trim",
+ "predicate": {
+ "trim_type": 0.4
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_copper_trim",
+ "predicate": {
+ "trim_type": 0.5
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_gold_trim",
+ "predicate": {
+ "trim_type": 0.6
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_emerald_trim",
+ "predicate": {
+ "trim_type": 0.7
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_diamond_trim",
+ "predicate": {
+ "trim_type": 0.8
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_lapis_trim",
+ "predicate": {
+ "trim_type": 0.9
+ }
+ },
+ {
+ "model": "minecraft:item/leather_boots_amethyst_trim",
+ "predicate": {
+ "trim_type": 1.0
+ }
+ }
+ ],
+ "textures": {
+ "layer0": "minecraft:item/leather_boots",
+ "layer1": "minecraft:item/leather_boots_overlay"
+ }
+}
diff --git a/resource-pack/assets/minecraft/models/item/leather_chestplate.json b/resource-pack/assets/minecraft/models/item/leather_chestplate.json
new file mode 100644
index 00000000..d6dc8c5f
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/leather_chestplate.json
@@ -0,0 +1,75 @@
+{
+ "parent": "minecraft:item/generated",
+ "overrides": [
+ {
+ "model": "openinv:item/empty_chestplate",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_quartz_trim",
+ "predicate": {
+ "trim_type": 0.1
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_iron_trim",
+ "predicate": {
+ "trim_type": 0.2
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_netherite_trim",
+ "predicate": {
+ "trim_type": 0.3
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_redstone_trim",
+ "predicate": {
+ "trim_type": 0.4
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_copper_trim",
+ "predicate": {
+ "trim_type": 0.5
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_gold_trim",
+ "predicate": {
+ "trim_type": 0.6
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_emerald_trim",
+ "predicate": {
+ "trim_type": 0.7
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_diamond_trim",
+ "predicate": {
+ "trim_type": 0.8
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_lapis_trim",
+ "predicate": {
+ "trim_type": 0.9
+ }
+ },
+ {
+ "model": "minecraft:item/leather_chestplate_amethyst_trim",
+ "predicate": {
+ "trim_type": 1.0
+ }
+ }
+ ],
+ "textures": {
+ "layer0": "minecraft:item/leather_chestplate",
+ "layer1": "minecraft:item/leather_chestplate_overlay"
+ }
+}
diff --git a/resource-pack/assets/minecraft/models/item/leather_helmet.json b/resource-pack/assets/minecraft/models/item/leather_helmet.json
new file mode 100644
index 00000000..236ae610
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/leather_helmet.json
@@ -0,0 +1,75 @@
+{
+ "parent": "minecraft:item/generated",
+ "overrides": [
+ {
+ "model": "openinv:item/empty_helmet",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_quartz_trim",
+ "predicate": {
+ "trim_type": 0.1
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_iron_trim",
+ "predicate": {
+ "trim_type": 0.2
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_netherite_trim",
+ "predicate": {
+ "trim_type": 0.3
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_redstone_trim",
+ "predicate": {
+ "trim_type": 0.4
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_copper_trim",
+ "predicate": {
+ "trim_type": 0.5
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_gold_trim",
+ "predicate": {
+ "trim_type": 0.6
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_emerald_trim",
+ "predicate": {
+ "trim_type": 0.7
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_diamond_trim",
+ "predicate": {
+ "trim_type": 0.8
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_lapis_trim",
+ "predicate": {
+ "trim_type": 0.9
+ }
+ },
+ {
+ "model": "minecraft:item/leather_helmet_amethyst_trim",
+ "predicate": {
+ "trim_type": 1.0
+ }
+ }
+ ],
+ "textures": {
+ "layer0": "minecraft:item/leather_helmet",
+ "layer1": "minecraft:item/leather_helmet_overlay"
+ }
+}
diff --git a/resource-pack/assets/minecraft/models/item/leather_leggings.json b/resource-pack/assets/minecraft/models/item/leather_leggings.json
new file mode 100644
index 00000000..eb9ddc89
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/leather_leggings.json
@@ -0,0 +1,75 @@
+{
+ "parent": "minecraft:item/generated",
+ "overrides": [
+ {
+ "model": "openinv:item/empty_leggings",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_quartz_trim",
+ "predicate": {
+ "trim_type": 0.1
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_iron_trim",
+ "predicate": {
+ "trim_type": 0.2
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_netherite_trim",
+ "predicate": {
+ "trim_type": 0.3
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_redstone_trim",
+ "predicate": {
+ "trim_type": 0.4
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_copper_trim",
+ "predicate": {
+ "trim_type": 0.5
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_gold_trim",
+ "predicate": {
+ "trim_type": 0.6
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_emerald_trim",
+ "predicate": {
+ "trim_type": 0.7
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_diamond_trim",
+ "predicate": {
+ "trim_type": 0.8
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_lapis_trim",
+ "predicate": {
+ "trim_type": 0.9
+ }
+ },
+ {
+ "model": "minecraft:item/leather_leggings_amethyst_trim",
+ "predicate": {
+ "trim_type": 1.0
+ }
+ }
+ ],
+ "textures": {
+ "layer0": "minecraft:item/leather_leggings",
+ "layer1": "minecraft:item/leather_leggings_overlay"
+ }
+}
diff --git a/resource-pack/assets/minecraft/models/item/shield.json b/resource-pack/assets/minecraft/models/item/shield.json
new file mode 100644
index 00000000..5ea7eddd
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/shield.json
@@ -0,0 +1,58 @@
+{
+ "parent": "builtin/entity",
+ "gui_light": "front",
+ "textures": {
+ "particle": "block/dark_oak_planks"
+ },
+ "display": {
+ "thirdperson_righthand": {
+ "rotation": [ 0, 90, 0 ],
+ "translation": [ 10, 6, -4 ],
+ "scale": [ 1, 1, 1 ]
+ },
+ "thirdperson_lefthand": {
+ "rotation": [ 0, 90, 0 ],
+ "translation": [ 10, 6, 12 ],
+ "scale": [ 1, 1, 1 ]
+ },
+ "firstperson_righthand": {
+ "rotation": [ 0, 180, 5 ],
+ "translation": [ -10, 2, -10 ],
+ "scale": [ 1.25, 1.25, 1.25 ]
+ },
+ "firstperson_lefthand": {
+ "rotation": [ 0, 180, 5 ],
+ "translation": [ 10, 0, -10 ],
+ "scale": [ 1.25, 1.25, 1.25 ]
+ },
+ "gui": {
+ "rotation": [ 15, -25, -5 ],
+ "translation": [ 2, 3, 0 ],
+ "scale": [ 0.65, 0.65, 0.65 ]
+ },
+ "fixed": {
+ "rotation": [ 0, 180, 0 ],
+ "translation": [ -4.5, 4.5, -5],
+ "scale":[ 0.55, 0.55, 0.55]
+ },
+ "ground": {
+ "rotation": [ 0, 0, 0 ],
+ "translation": [ 2, 4, 2],
+ "scale":[ 0.25, 0.25, 0.25]
+ }
+ },
+ "overrides": [
+ {
+ "model": "openinv:item/empty_shield",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ },
+ {
+ "predicate": {
+ "blocking": 1
+ },
+ "model": "item/shield_blocking"
+ }
+ ]
+}
diff --git a/resource-pack/assets/minecraft/models/item/white_banner.json b/resource-pack/assets/minecraft/models/item/white_banner.json
new file mode 100644
index 00000000..bc6fadb8
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/white_banner.json
@@ -0,0 +1,11 @@
+{
+ "parent": "minecraft:item/template_banner",
+ "overrides": [
+ {
+ "model": "openinv:item/cursor",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ }
+ ]
+}
diff --git a/resource-pack/assets/minecraft/models/item/white_stained_glass_pane.json b/resource-pack/assets/minecraft/models/item/white_stained_glass_pane.json
new file mode 100644
index 00000000..66dbd7d2
--- /dev/null
+++ b/resource-pack/assets/minecraft/models/item/white_stained_glass_pane.json
@@ -0,0 +1,14 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "minecraft:item/white_stained_glass_pane"
+ },
+ "overrides": [
+ {
+ "model": "openinv:item/not_a_slot",
+ "predicate": {
+ "custom_model_data": 9999
+ }
+ }
+ ]
+}
diff --git a/resource-pack/assets/openinv/models/item/crafting_output.json b/resource-pack/assets/openinv/models/item/crafting_output.json
new file mode 100644
index 00000000..6c167cdc
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/crafting_output.json
@@ -0,0 +1,24 @@
+{
+ "texture_size": [ 16, 32 ],
+ "textures": {
+ "layer0": "openinv:item/crafting_output"
+ },
+ "elements": [
+ {
+ "from": [ 0, -16, -16 ],
+ "to": [ 16, 16, -16 ],
+ "faces": {
+ "south": {
+ "uv": [ 0, 0, 16, 16 ],
+ "texture": "#layer0"
+ }
+ }
+ }
+ ],
+ "gui_light": "front",
+ "display": {
+ "gui": {
+ "scale": [ 1.125, 1.125, 1 ]
+ }
+ }
+}
diff --git a/resource-pack/assets/openinv/models/item/cursor.json b/resource-pack/assets/openinv/models/item/cursor.json
new file mode 100644
index 00000000..6c033d83
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/cursor.json
@@ -0,0 +1,6 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "openinv:item/cursor"
+ }
+}
diff --git a/resource-pack/assets/openinv/models/item/drop.json b/resource-pack/assets/openinv/models/item/drop.json
new file mode 100644
index 00000000..b4782491
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/drop.json
@@ -0,0 +1,6 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "openinv:item/drop"
+ }
+}
diff --git a/resource-pack/assets/openinv/models/item/empty_boots.json b/resource-pack/assets/openinv/models/item/empty_boots.json
new file mode 100644
index 00000000..5b3ddf27
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/empty_boots.json
@@ -0,0 +1,6 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "minecraft:item/empty_armor_slot_boots"
+ }
+}
diff --git a/resource-pack/assets/openinv/models/item/empty_chestplate.json b/resource-pack/assets/openinv/models/item/empty_chestplate.json
new file mode 100644
index 00000000..4003d627
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/empty_chestplate.json
@@ -0,0 +1,6 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "minecraft:item/empty_armor_slot_chestplate"
+ }
+}
diff --git a/resource-pack/assets/openinv/models/item/empty_helmet.json b/resource-pack/assets/openinv/models/item/empty_helmet.json
new file mode 100644
index 00000000..dda818a6
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/empty_helmet.json
@@ -0,0 +1,6 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "minecraft:item/empty_armor_slot_helmet"
+ }
+}
diff --git a/resource-pack/assets/openinv/models/item/empty_leggings.json b/resource-pack/assets/openinv/models/item/empty_leggings.json
new file mode 100644
index 00000000..c74e7e2a
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/empty_leggings.json
@@ -0,0 +1,6 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "minecraft:item/empty_armor_slot_leggings"
+ }
+}
diff --git a/resource-pack/assets/openinv/models/item/empty_shield.json b/resource-pack/assets/openinv/models/item/empty_shield.json
new file mode 100644
index 00000000..6e6b21c1
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/empty_shield.json
@@ -0,0 +1,6 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "minecraft:item/empty_armor_slot_shield"
+ }
+}
diff --git a/resource-pack/assets/openinv/models/item/not_a_slot.json b/resource-pack/assets/openinv/models/item/not_a_slot.json
new file mode 100644
index 00000000..a4955524
--- /dev/null
+++ b/resource-pack/assets/openinv/models/item/not_a_slot.json
@@ -0,0 +1,11 @@
+{
+ "parent": "minecraft:item/generated",
+ "textures": {
+ "layer0": "openinv:item/not_a_slot"
+ },
+ "display": {
+ "gui": {
+ "scale": [ 1.125, -1.125, -1.125 ]
+ }
+ }
+}
diff --git a/resource-pack/assets/openinv/textures/item/crafting_output.png b/resource-pack/assets/openinv/textures/item/crafting_output.png
new file mode 100644
index 00000000..7590bb45
Binary files /dev/null and b/resource-pack/assets/openinv/textures/item/crafting_output.png differ
diff --git a/resource-pack/assets/openinv/textures/item/cursor.png b/resource-pack/assets/openinv/textures/item/cursor.png
new file mode 100644
index 00000000..af54bc59
Binary files /dev/null and b/resource-pack/assets/openinv/textures/item/cursor.png differ
diff --git a/resource-pack/assets/openinv/textures/item/drop.png b/resource-pack/assets/openinv/textures/item/drop.png
new file mode 100644
index 00000000..8caf814e
Binary files /dev/null and b/resource-pack/assets/openinv/textures/item/drop.png differ
diff --git a/resource-pack/assets/openinv/textures/item/not_a_slot.png b/resource-pack/assets/openinv/textures/item/not_a_slot.png
new file mode 100644
index 00000000..300e19d2
Binary files /dev/null and b/resource-pack/assets/openinv/textures/item/not_a_slot.png differ
diff --git a/resource-pack/pack.mcmeta b/resource-pack/pack.mcmeta
new file mode 100644
index 00000000..51a24480
--- /dev/null
+++ b/resource-pack/pack.mcmeta
@@ -0,0 +1,6 @@
+{
+ "pack": {
+ "description": "Improve OpenInv's legibility",
+ "pack_format": 34
+ }
+}