Skip to content

Commit

Permalink
Improve customizability, add resource pack (#215)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jikoo authored Jul 5, 2024
1 parent 09b3f83 commit e39dbc0
Show file tree
Hide file tree
Showing 38 changed files with 803 additions and 216 deletions.
9 changes: 8 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -252,35 +252,58 @@ 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());
}
};
container.setTitle(title);

container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container);
container = CraftEventFactory.callInventoryOpenEvent(player, container);

if (container == null) {
return null;
Expand All @@ -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();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
*
* <p>Unmodifiable because I said so. Use your own crafting grid.</p>
*/
class ContainerSlotCraftingResult extends ContainerSlotEmpty {
class ContainerSlotCraftingResult extends ContainerSlotUninteractable {

ContainerSlotCraftingResult(@NotNull ServerPlayer holder) {
super(holder);
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
@@ -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<BannerPattern> 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) {
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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<BannerPattern> 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;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}

Expand Down Expand Up @@ -74,7 +64,7 @@ static class SlotEmpty extends MenuSlotPlaceholder {

@Override
ItemStack getOrDefault() {
return PLACEHOLDER;
return PlaceholderManager.notSlot;
}

public void onQuickCraft(ItemStack var0, ItemStack var1) {}
Expand Down
Loading

0 comments on commit e39dbc0

Please sign in to comment.