Compare commits

...
8 Commits
Author SHA1 Message Date
Jikoo 55053dacbf Bump version to 5.3.3 for release 2026-06-28 10:24:30 -04:00
KalkaandJikoo dacb07bd41 Update to Minecraft 26.2 (#406)
* Add support for Minecraft 26.2
* Update resource pack version
* Drop support for Minecraft 1.21.6-1.21.8
* Drop internal version listing

---------

Co-authored-by: Jikoo <jikoo.games@gmail.com>
2026-06-28 10:17:18 -04:00
dependabot[bot] 06d3fd7df9 Bump org.slf4j:slf4j-api from 2.0.17 to 2.0.18 (#404) 2026-06-03 01:11:53 +00:00
dependabot[bot] 4acf43b0fe Bump gradle-wrapper from 9.5.0 to 9.5.1 (#402) 2026-06-03 01:11:49 +00:00
dependabot[bot] a570001eaf Bump com.gradleup.shadow from 9.4.1 to 9.4.2 (#403) 2026-06-03 01:10:57 +00:00
Jikoo 70c53521c1 Update release template 2026-05-22 11:01:44 -04:00
Jikoo 9021ef9a22 Explicitly disable Modrinth unfeaturing
Docs suggest that this should not be necessary if featured management is not enabled, but here we are.
2026-05-22 10:55:36 -04:00
Jikoo 722ab4d2a3 Bump version to 5.3.3-SNAPSHOT for development 2026-05-22 10:05:45 -04:00
91 changed files with 1384 additions and 1425 deletions

No files matched your search

+4 -2
View File
@@ -24,13 +24,15 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
name: OpenInv ${{ env.VERSIONED_NAME }}
name: "OpenInv ${{ github.ref_name }}"
body: |-
## Supported server versions
**Paper:** TODO VERSION, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.1
**Paper:** TODO VERSION, 26.1.2, 1.21.11, 1.21.10, 1.21.9, 1.21.8, 1.21.7, 1.21.6
**Spigot:** TODO VERSION
TODO HELLO HUMAN, PRESS THE GENERATE CHANGELOG BUTTON PLEASE.
Don't forget to add a newline after the resulting header and prettify the tag compare link!
draft: true
prerelease: false
files: ./dist/**
+1
View File
@@ -59,6 +59,7 @@ jobs:
with:
modrinth-id: 1UlvXbzL
modrinth-featured: false
modrinth-unfeature-mode: none
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
files: ./OpenInv.jar
game-versions: "${{ steps.parse_versions.outputs.PAPER_VERSIONS }}"
+1 -1
View File
@@ -1,6 +1,6 @@
# Project meta
group=com.lishid.openinv
version=5.3.2
version=5.3.3
description=A Bukkit plugin for opening normally-inaccessible inventories.
# Gradle configuration
+2 -2
View File
@@ -4,11 +4,11 @@ planarwrappers = "3.3.0"
jspecify = "1.0.0"
annotations = "26.1.0"
paperweight = "2.0.0-beta.21"
shadow = "9.4.1"
shadow = "9.4.2"
folia-scheduler-wrapper = "v0.0.3"
errorprone-core = "2.49.0"
errorprone-gradle = "5.1.0"
slf4j = "2.0.17"
slf4j = "2.0.18"
sqlite-jdbc = "3.49.1.0"
[libraries]
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.0-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
@@ -1,8 +1,8 @@
package com.lishid.openinv.internal.paper1_21_10.container;
import com.lishid.openinv.internal.paper1_21_11.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_2.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenChestMenu;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FontDescription;
@@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
public class OpenPlayer extends com.lishid.openinv.internal.paper26_1.player.OpenPlayer {
public class OpenPlayer extends com.lishid.openinv.internal.paper26_2.player.OpenPlayer {
protected OpenPlayer(
CraftServer server,
@@ -1,14 +1,14 @@
package com.lishid.openinv.internal.paper1_21_11.container;
import com.lishid.openinv.internal.paper1_21_11.container.menu.OpenEnderChestMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenChestMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenEnderChest extends com.lishid.openinv.internal.paper26_1.container.OpenEnderChest {
public class OpenEnderChest extends com.lishid.openinv.internal.paper26_2.container.OpenEnderChest {
public OpenEnderChest(org.bukkit.entity.Player player) {
super(player);
@@ -1,14 +1,14 @@
package com.lishid.openinv.internal.paper1_21_11.container;
import com.lishid.openinv.internal.paper1_21_11.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenChestMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import org.jetbrains.annotations.Nullable;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class OpenInventory extends com.lishid.openinv.internal.paper26_1.container.OpenInventory {
public class OpenInventory extends com.lishid.openinv.internal.paper26_2.container.OpenInventory {
public OpenInventory(org.bukkit.entity.Player bukkitPlayer) {
super(bukkitPlayer);
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.paper1_21_11.container.menu;
import com.lishid.openinv.internal.paper26_1.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenSyncMenu;
import com.lishid.openinv.internal.paper26_2.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenSyncMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ClickType;
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.paper1_21_11.container.menu;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.menu.BaseOpenInventoryMenu;
import com.lishid.openinv.internal.paper26_2.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_2.container.menu.BaseOpenInventoryMenu;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ClickType;
-28
View File
@@ -1,28 +0,0 @@
plugins {
alias(libs.plugins.paperweight)
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(21)
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
dependencies {
implementation(project(":openinvapi")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvcommon")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvadapterpaper26_1")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
implementation(project(":openinvadapterpaper1_21_11")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
paperweight.paperDevBundle("1.21.8-R0.1-SNAPSHOT")
}
@@ -1,31 +0,0 @@
package com.lishid.openinv.internal.paper1_21_8;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.paper1_21_8.container.OpenInventory;
import com.lishid.openinv.internal.paper1_21_8.player.PlayerManager;
import com.lishid.openinv.util.lang.LanguageManager;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
public class InternalAccessor extends com.lishid.openinv.internal.paper1_21_11.InternalAccessor {
private final @NotNull PlayerManager manager;
public InternalAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
super(logger, lang);
manager = new PlayerManager(logger);
}
@Override
public @NotNull PlayerManager getPlayerManager() {
return manager;
}
@Override
public @NotNull ISpecialPlayerInventory createPlayerInventory(@NotNull Player player) {
return new OpenInventory(player);
}
}
@@ -1,58 +0,0 @@
package com.lishid.openinv.internal.paper1_21_8.container;
import com.lishid.openinv.internal.paper1_21_11.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerPlayer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class OpenInventory extends BaseOpenInventory {
public OpenInventory(@NotNull Player bukkitPlayer) {
super(bukkitPlayer);
}
@Override
public @NotNull Component getTitle(@Nullable ServerPlayer viewer, @Nullable OpenChestMenu<?> menu) {
MutableComponent component = Component.empty();
// Prefix for use with custom bitmap image fonts.
if (owner.equals(viewer)) {
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)));
}
if (menu != null && menu.isViewOnly()) {
component.append(Component.translatableWithFallback("openinv.container.inventory.viewonly", "[RO] "));
} else {
component.append(Component.translatableWithFallback("openinv.container.inventory.editable", ""));
}
// Normal title: "Inventory - OwnerName"
component.append(Component.translatableWithFallback("openinv.container.inventory.prefix", "", owner.getName()))
.append(Component.translatable("container.inventory"))
.append(Component.translatableWithFallback("openinv.container.inventory.suffix", " - %s", owner.getName()));
return component;
}
@Override
public @Nullable OpenChestMenu<?> createMenu(net.minecraft.world.entity.player.Player player, int i, boolean viewOnly) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenInventoryMenu(this, serverPlayer, i, viewOnly);
}
return null;
}
}
@@ -1,44 +0,0 @@
package com.lishid.openinv.internal.paper1_21_8.player;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.level.storage.PlayerDataStorage;
import org.bukkit.craftbukkit.CraftServer;
import org.jetbrains.annotations.NotNull;
import java.nio.file.Path;
import java.util.Optional;
public class OpenPlayer extends com.lishid.openinv.internal.paper26_1.player.OpenPlayer {
protected OpenPlayer(
CraftServer server,
ServerPlayer entity,
PlayerManager manager
) {
super(server, entity, manager);
}
@Override
protected Optional<CompoundTag> load(
PlayerDataStorage storage,
ServerPlayer player,
ProblemReporter.ScopedCollector collector
) {
return storage.load(player.getName().getString(), player.getStringUUID(), collector);
}
@Override
protected void safeReplaceFile(@NotNull Path dataFile, @NotNull Path tempFile, @NotNull Path backupFile) {
net.minecraft.Util.safeReplaceFile(dataFile, tempFile, backupFile);
}
@Override
protected void remove(@NotNull CompoundTag tag, @NotNull String key) {
// Note that the method signature here is different, though the usage
// appears identical. This version does not return the removed tag.
tag.remove(key);
}
}
@@ -1,100 +0,0 @@
package com.lishid.openinv.internal.paper1_21_8.player;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import com.lishid.openinv.util.JulLoggerAdapter;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.ValueInput;
import org.bukkit.Bukkit;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.logging.Logger;
public class PlayerManager extends com.lishid.openinv.internal.paper26_1.player.PlayerManager {
public PlayerManager(@NotNull Logger logger) {
super(logger);
}
@Override
protected boolean loadData(@NotNull MinecraftServer server, @NotNull ServerPlayer player) {
// See CraftPlayer#loadData
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), new JulLoggerAdapter(logger))) {
ValueInput loadedData = server.getPlayerList().playerIo.load(player, scopedCollector).orElse(null);
if (loadedData == null) {
// Exceptions with loading are logged.
return false;
}
// Read basic data into the player.
player.load(loadedData);
// Game type settings are loaded separately.
player.loadGameTypes(loadedData);
// World is not loaded by ServerPlayer#load(CompoundTag) on Paper.
parseWorld(server, player, loadedData);
}
return true;
}
@Override
protected void spawnInDefaultWorld(@NotNull MinecraftServer server, @NotNull ServerPlayer player) {
ServerLevel level = server.getLevel(Level.OVERWORLD);
if (level != null) {
// Adjust player to default spawn (in keeping with Paper handling) when world not found.
player.snapTo(player.adjustSpawnLocation(level, level.getSharedSpawnPos()).getBottomCenter(), level.getSharedSpawnAngle(), 0.0F);
player.spawnIn(level);
} else {
logger.warning("Tried to load player with invalid world when no fallback was available!");
}
}
@Override
protected void injectPlayer(@NotNull MinecraftServer server, @NotNull ServerPlayer player) throws IllegalAccessException {
if (bukkitEntity == null) {
return;
}
bukkitEntity.setAccessible(true);
bukkitEntity.set(player, new com.lishid.openinv.internal.paper1_21_8.player.OpenPlayer(server.server, player, this));
}
@Override
public @NotNull Player inject(@NotNull Player player) {
try {
ServerPlayer nmsPlayer = getHandle(player);
if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) {
return openPlayer;
}
MinecraftServer server = nmsPlayer.getServer();
if (server == null) {
if (!(Bukkit.getServer() instanceof CraftServer craftServer)) {
logger.warning(() ->
"Unable to inject ServerPlayer, certain player data may be lost when saving! Server is not a CraftServer: "
+ Bukkit.getServer().getClass().getName());
return player;
}
server = craftServer.getServer();
}
injectPlayer(server, nmsPlayer);
return nmsPlayer.getBukkitEntity();
} catch (IllegalAccessException e) {
logger.log(
java.util.logging.Level.WARNING,
e,
() -> "Unable to inject ServerPlayer, certain player data may be lost when saving!"
);
return player;
}
}
}
+3
View File
@@ -57,6 +57,9 @@ dependencies {
implementation(project(":openinvcommon")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
api(project(":openinvadapterpaper26_2")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
paperweight.paperDevBundle("26.1.2.build.5-alpha")
}
@@ -1,52 +1,38 @@
package com.lishid.openinv.internal.paper26_1;
import com.lishid.openinv.internal.Accessor;
import com.lishid.openinv.internal.IAnySilentContainer;
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.paper26_1.container.AnySilentContainer;
import com.lishid.openinv.internal.paper26_1.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_1.container.OpenInventory;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.PlaceholderLoader;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.PlaceholderLoader;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.world.Container;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.logging.Level;
import java.util.logging.Logger;
public class InternalAccessor implements Accessor {
protected final @NotNull Logger logger;
private final @NotNull PlayerManager manager;
private final @NotNull AnySilentContainer anySilentContainer;
public class InternalAccessor extends com.lishid.openinv.internal.paper26_2.InternalAccessor {
public InternalAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
this.logger = logger;
manager = new PlayerManager(logger);
anySilentContainer = new AnySilentContainer(logger, lang);
super(logger, lang);
}
@Override
public @NotNull PlayerManager getPlayerManager() {
return manager;
protected @NotNull PlayerManager createPlayerManager(@NotNull Logger logger) {
return new PlayerManager(logger);
}
@Override
public @NotNull IAnySilentContainer getAnySilentContainer() {
return anySilentContainer;
protected @NotNull AnySilentContainer createAnySilentContainer(
@NotNull Logger logger,
@NotNull LanguageManager lang
) {
return new AnySilentContainer(logger, lang);
}
@Override
public @NotNull ISpecialPlayerInventory createPlayerInventory(@NotNull Player player) {
return new OpenInventory(player);
protected @NotNull PlaceholderLoader createPlaceholderLoader() {
return new com.lishid.openinv.internal.paper26_1.container.slot.placeholder.PlaceholderLoader();
}
@Override
@@ -54,27 +40,4 @@ public class InternalAccessor implements Accessor {
return new OpenEnderChest(player);
}
@Override
public <T extends ISpecialInventory> @Nullable T get(@NotNull Inventory bukkitInventory, @NotNull Class<T> clazz) {
if (!(bukkitInventory instanceof CraftInventory craftInventory)) {
return null;
}
Container container = craftInventory.getInventory();
if (clazz.isInstance(container)) {
return clazz.cast(container);
}
return null;
}
@Override
public void reload(@NotNull ConfigurationSection config) {
ConfigurationSection placeholders = config.getConfigurationSection("placeholders");
try {
// Reset placeholders to defaults and try to load configuration.
new PlaceholderLoader().load(placeholders);
} catch (Exception e) {
logger.log(Level.WARNING, "Caught exception loading placeholder overrides!", e);
}
}
}
@@ -1,228 +1,20 @@
/*
* Copyright (C) 2011-2023 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.paper26_1.container;
import com.lishid.openinv.internal.AnySilentContainerBase;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import com.lishid.openinv.util.ReflectionHelper;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.PlayerEnderChestContainer;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.block.BarrelBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.ShulkerBoxBlock;
import net.minecraft.world.level.block.TrappedChestBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.EnderChestBlockEntity;
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.logging.Logger;
public class AnySilentContainer extends AnySilentContainerBase {
private final @NotNull Logger logger;
private final @NotNull LanguageManager lang;
private @Nullable Field serverPlayerGameModeGameType;
public class AnySilentContainer extends com.lishid.openinv.internal.paper26_2.container.AnySilentContainer {
public AnySilentContainer(@NotNull Logger logger, @NotNull LanguageManager lang) {
this.logger = logger;
this.lang = lang;
try {
try {
this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("gameModeForPlayer");
this.serverPlayerGameModeGameType.setAccessible(true);
} catch (NoSuchFieldException e) {
logger.warning("The field ServerPlayerGameMode#gameModeForPlayer is no longer present!");
logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues");
logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail.");
// N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break.
this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class);
}
} catch (SecurityException e) {
logger.warning("Unable to directly write player game mode! SilentContainer will fail.");
logger.log(java.util.logging.Level.WARNING, "Error obtaining GameType field", e);
}
super(logger, lang);
}
@Override
public boolean activateContainer(
@NotNull final Player bukkitPlayer,
final boolean silentchest,
@NotNull final org.bukkit.block.Block bukkitBlock
) {
// Silent ender chest is API-only
if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) {
bukkitPlayer.openInventory(bukkitPlayer.getEnderChest());
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true;
}
ServerPlayer player = PlayerManager.getHandle(bukkitPlayer);
final net.minecraft.world.level.Level level = ((Entity) player).level();
final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());
final BlockEntity blockEntity = level.getBlockEntity(blockPos);
if (blockEntity == null) {
return false;
}
if (blockEntity instanceof EnderChestBlockEntity enderChestTile) {
// Anychest ender chest. See net.minecraft.world.level.block.EnderChestBlock
PlayerEnderChestContainer enderChest = player.getEnderChestInventory();
enderChest.setActiveChest(enderChestTile);
player.openMenu(
new SimpleMenuProvider(
(containerCounter, playerInventory, ignored) -> {
MenuType<?> containers = OpenChestMenu.getChestMenuType(enderChest.getContainerSize());
int rows = enderChest.getContainerSize() / 9;
return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows);
}, Component.translatable("container.enderchest")
)
);
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true;
}
if (!(blockEntity instanceof MenuProvider menuProvider)) {
return false;
}
BlockState blockState = level.getBlockState(blockPos);
Block block = blockState.getBlock();
if (block instanceof ChestBlock chestBlock) {
// boolean flag: do not check if chest is blocked
menuProvider = chestBlock.getMenuProvider(blockState, level, blockPos, true);
if (menuProvider == null) {
lang.sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false;
}
if (block instanceof TrappedChestBlock) {
bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED);
} else {
bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED);
}
}
if (block instanceof ShulkerBoxBlock) {
bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED);
}
if (block instanceof BarrelBlock) {
bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL);
}
// AnyChest only - SilentChest not active, container unsupported, or unnecessary.
if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) {
player.openMenu(menuProvider);
return true;
}
// SilentChest requires access to setting players' game mode directly.
if (this.serverPlayerGameModeGameType == null) {
return false;
}
if (blockEntity instanceof RandomizableContainerBlockEntity lootable) {
if (lootable.lootTable != null) {
lang.sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false;
}
}
GameType gameType = player.gameMode.getGameModeForPlayer();
this.forceGameType(player, GameType.SPECTATOR);
player.openMenu(menuProvider);
this.forceGameType(player, gameType);
return true;
}
@Override
public void deactivateContainer(@NotNull final Player bukkitPlayer) {
if (this.serverPlayerGameModeGameType == null || bukkitPlayer.getGameMode() == GameMode.SPECTATOR) {
return;
}
ServerPlayer player = PlayerManager.getHandle(bukkitPlayer);
// Force game mode change without informing plugins or players.
// Regular game mode set calls GameModeChangeEvent and is cancellable.
GameType gameType = player.gameMode.getGameModeForPlayer();
this.forceGameType(player, GameType.SPECTATOR);
// ServerPlayer#closeContainer cannot be called without entering an
// infinite loop because this method is called during inventory close.
// From ServerPlayer#closeContainer -> CraftEventFactory#handleInventoryCloseEvent
player.containerMenu.transferTo(player.inventoryMenu, player.getBukkitEntity());
// From ServerPlayer#closeContainer
player.doCloseContainer();
// Regular inventory close will handle the rest - packet sending, etc.
// Revert forced game mode.
this.forceGameType(player, gameType);
}
private void forceGameType(final ServerPlayer player, final GameType gameMode) {
if (this.serverPlayerGameModeGameType == null) {
// No need to warn repeatedly, error on startup and lack of function should be enough.
return;
}
try {
this.serverPlayerGameModeGameType.setAccessible(true);
this.serverPlayerGameModeGameType.set(player.gameMode, gameMode);
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.log(java.util.logging.Level.WARNING, "Error bypassing GameModeChangeEvent", e);
}
}
@Override
protected org.bukkit.block.BlockState getState(@NotNull org.bukkit.block.Block block) {
return block.getState(false);
}
@Override
protected InventoryHolder getHolder(@NotNull Inventory inventory) {
return inventory.getHolder(false);
protected boolean hasLootTable(@NotNull RandomizableContainerBlockEntity lootable) {
return lootable.lootTable != null;
}
}
@@ -1,201 +1,19 @@
package com.lishid.openinv.internal.paper26_1.container;
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenEnderChestMenu;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.player.StackedItemContents;
import net.minecraft.world.inventory.StackedContentsCompatible;
import net.minecraft.world.item.ItemStack;
import org.bukkit.Location;
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class OpenEnderChest implements Container, StackedContentsCompatible, InternalOwned<ServerPlayer>,
ISpecialEnderChest {
private CraftInventory inventory;
private @NotNull ServerPlayer owner;
private NonNullList<ItemStack> items;
private int maxStack = 64;
private final List<HumanEntity> transaction = new ArrayList<>();
public class OpenEnderChest extends com.lishid.openinv.internal.paper26_2.container.OpenEnderChest {
public OpenEnderChest(@NotNull org.bukkit.entity.Player player) {
this.owner = PlayerManager.getHandle(player);
this.items = owner.getEnderChestInventory().items;
super(player);
}
@Override
public @NotNull ServerPlayer getOwnerHandle() {
return owner;
}
@Override
public @NotNull org.bukkit.inventory.Inventory getBukkitInventory() {
if (inventory == null) {
inventory = new CraftInventory(this) {
@Override
public @NotNull InventoryType getType() {
return InventoryType.ENDER_CHEST;
}
};
}
return inventory;
}
@Override
public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) {
owner = PlayerManager.getHandle(player);
NonNullList<ItemStack> activeItems = owner.getEnderChestInventory().items;
// Guard against size changing. Theoretically on Purpur all row variations still have 6 rows internally.
int max = Math.min(items.size(), activeItems.size());
for (int index = 0; index < max; ++index) {
activeItems.set(index, items.get(index));
}
items = activeItems;
}
@Override
public @NotNull org.bukkit.entity.Player getPlayer() {
return owner.getBukkitEntity();
}
@Override
public int getContainerSize() {
return items.size();
}
@Override
public boolean isEmpty() {
return items.stream().allMatch(ItemStack::isEmpty);
}
@Override
public @NotNull ItemStack getItem(int index) {
return index >= 0 && index < items.size() ? items.get(index) : ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack removeItem(int index, int amount) {
ItemStack itemstack = ContainerHelper.removeItem(items, index, amount);
if (!itemstack.isEmpty()) {
setChanged();
}
return itemstack;
}
@Override
public @NotNull ItemStack removeItemNoUpdate(int index) {
return index >= 0 && index < items.size() ? items.set(index, ItemStack.EMPTY) : ItemStack.EMPTY;
}
@Override
public void setItem(int index, @NotNull ItemStack itemStack) {
if (index >= 0 && index < items.size()) {
items.set(index, itemStack);
}
}
@Override
public int getMaxStackSize() {
return maxStack;
}
@Override
public void setChanged() {
this.owner.getEnderChestInventory().setChanged();
}
@Override
public boolean stillValid(@NotNull Player player) {
return true;
}
@Override
public @NotNull List<ItemStack> getContents() {
return items;
}
@Override
public void onOpen(@NotNull CraftHumanEntity craftHumanEntity) {
transaction.add(craftHumanEntity);
}
@Override
public void onClose(@NotNull CraftHumanEntity craftHumanEntity) {
transaction.remove(craftHumanEntity);
}
@Override
public @NotNull List<HumanEntity> getViewers() {
return transaction;
}
@Override
public org.bukkit.entity.Player getOwner() {
return getPlayer();
}
@Override
public void setMaxStackSize(int size) {
maxStack = size;
}
@Override
public @Nullable Location getLocation() {
return null;
}
@Override
public void clearContent() {
items.clear();
setChanged();
}
@Override
public void fillStackedContents(@NotNull StackedItemContents stackedContents) {
for (ItemStack itemstack : items) {
stackedContents.accountStack(itemstack);
}
}
public Component getTitle(@Nullable OpenChestMenu<?> menu) {
MutableComponent component;
if (menu != null && menu.isViewOnly()) {
component = Component.translatableWithFallback("openinv.container.enderchest.viewonly", "[RO] ");
} else {
component = Component.translatableWithFallback("openinv.container.enderchest.editable", "");
}
return component
.append(Component.translatableWithFallback("openinv.container.enderchest.prefix", "", owner.getName()))
.append(Component.translatable("container.enderchest"))
.append(Component.translatableWithFallback("openinv.container.enderchest.suffix", " - %s", owner.getName()));
}
public @Nullable OpenChestMenu<?> createMenu(Player player, int i, boolean viewOnly) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenEnderChestMenu(this, serverPlayer, i, viewOnly);
}
return null;
protected @NotNull NonNullList<ItemStack> getEnderChestItems(@NotNull ServerPlayer owner) {
return owner.getEnderChestInventory().items;
}
}
@@ -1,40 +1,19 @@
package com.lishid.openinv.internal.paper26_1.container.slot.placeholder;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.TagParser;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.CustomModelData;
import net.minecraft.world.item.component.DyedItemColor;
import net.minecraft.world.item.component.TooltipDisplay;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashSet;
import java.util.List;
public class PlaceholderLoader extends PlaceholderLoaderBase {
private static final CustomModelData DEFAULT_CUSTOM_MODEL_DATA = new CustomModelData(List.of(), List.of(), List.of("openinv:custom"), List.of());
private static final TooltipDisplay HIDE_TOOLTIP = new TooltipDisplay(true, new LinkedHashSet<>());
public class PlaceholderLoader extends com.lishid.openinv.internal.paper26_2.container.slot.placeholder.PlaceholderLoader {
@Override
protected @NotNull CompoundTag parseTag(@NotNull String itemText) throws Exception {
return TagParser.parseCompoundFully(itemText);
protected @NotNull Item getDefaultCursorItem() {
return Items.WHITE_BANNER;
}
@Override
protected void addModelData(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
}
@Override
protected void hideTooltip(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.TOOLTIP_DISPLAY, HIDE_TOOLTIP);
}
@Override
protected DyedItemColor getDye(int rgb) {
return new DyedItemColor(rgb);
protected @NotNull Item getDefaultNotSlotItem() {
return Items.WHITE_STAINED_GLASS_PANE;
}
}
@@ -1,309 +1,42 @@
package com.lishid.openinv.internal.paper26_1.player;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.util.JulLoggerAdapter;
import com.mojang.authlib.GameProfile;
import com.mojang.logging.LogUtils;
import io.papermc.paper.adventure.PaperAdventure;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ClientInformation;
import net.minecraft.server.level.ParticleStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.ChatVisiblity;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.LevelData;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryView;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.Optional;
import java.util.UUID;
import java.util.logging.Logger;
@NullMarked
public class PlayerManager implements com.lishid.openinv.internal.PlayerManager {
protected final Logger logger;
protected @Nullable Field bukkitEntity;
public class PlayerManager extends com.lishid.openinv.internal.paper26_2.player.PlayerManager {
public PlayerManager(Logger logger) {
this.logger = logger;
try {
bukkitEntity = Entity.class.getDeclaredField("bukkitEntity");
} catch (NoSuchFieldException e) {
logger.warning("Unable to obtain field to inject custom save process - certain player data may be lost when saving!");
logger.log(java.util.logging.Level.WARNING, e.getMessage(), e);
bukkitEntity = null;
}
}
public static ServerPlayer getHandle(final Player player) {
if (player instanceof CraftPlayer craftPlayer) {
return craftPlayer.getHandle();
}
Server server = player.getServer();
ServerPlayer nmsPlayer = null;
if (server instanceof CraftServer craftServer) {
nmsPlayer = craftServer.getHandle().getPlayer(player.getUniqueId());
}
if (nmsPlayer == null) {
// Could use reflection to examine fields, but it's honestly not worth the bother.
throw new RuntimeException("Unable to fetch EntityPlayer from Player implementation " + player.getClass().getName());
}
return nmsPlayer;
super(logger);
}
@Override
public @Nullable Player loadPlayer(final OfflinePlayer offline) {
if (!(Bukkit.getServer() instanceof CraftServer craftServer)) {
return null;
}
MinecraftServer server = craftServer.getServer();
ServerLevel worldServer = server.getLevel(Level.OVERWORLD);
if (worldServer == null) {
return null;
}
// Create a new ServerPlayer.
ServerPlayer entity = createNewPlayer(server, worldServer, offline);
// Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak.
protected void removeAdvancementListeners(ServerPlayer entity) {
entity.getAdvancements().stopListening();
// Try to load the player's data.
if (loadData(server, entity)) {
// If data is loaded successfully, return the Bukkit entity.
return entity.getBukkitEntity();
}
return null;
}
protected ServerPlayer createNewPlayer(
MinecraftServer server,
ServerLevel worldServer,
final OfflinePlayer offline
) {
// See net.minecraft.server.players.PlayerList#canPlayerLogin(ServerLoginPacketListenerImpl, GameProfile)
// See net.minecraft.server.network.ServerLoginPacketListenerImpl#handleHello(ServerboundHelloPacket)
GameProfile profile = new GameProfile(offline.getUniqueId(),
offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()
);
ClientInformation dummyInfo = new ClientInformation(
"en_us",
1, // Reduce distance just in case.
ChatVisiblity.HIDDEN, // Don't accept chat.
false,
ServerPlayer.DEFAULT_MODEL_CUSTOMIZATION,
ServerPlayer.DEFAULT_MAIN_HAND,
true,
false, // Don't list in player list (not that this player is in the list anyway).
ParticleStatus.MINIMAL
);
ServerPlayer entity = new ServerPlayer(server, worldServer, profile, dummyInfo);
try {
injectPlayer(server, entity);
} catch (IllegalAccessException e) {
logger.log(
java.util.logging.Level.WARNING,
e,
() -> "Unable to inject ServerPlayer, certain player data may be lost when saving!"
);
}
return entity;
@Override
protected LevelData.RespawnData getRespawnData(ServerLevel level) {
return level.levelData.getRespawnData();
}
protected boolean loadData(MinecraftServer server, ServerPlayer player) {
// See CraftPlayer#loadData
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), new JulLoggerAdapter(logger))) {
CompoundTag loadedData = server.getPlayerList().playerIo.load(player.nameAndId()).orElse(null);
if (loadedData == null) {
// Exceptions with loading are logged.
return false;
}
ValueInput valueInput = TagValueInput.create(scopedCollector, player.registryAccess(), loadedData);
// Read basic data into the player.
player.load(valueInput);
// World is not loaded by ServerPlayer#load(CompoundTag) on Paper.
parseWorld(server, player, valueInput);
}
return true;
}
protected void parseWorld(
MinecraftServer server,
@Override
protected Vec3 getAdjustedSpawnLocation(
ServerPlayer player,
ValueInput loadedData
ServerLevel level,
LevelData.RespawnData respawnData
) {
// See PlayerList#placeNewPlayer
World bukkitWorld;
Optional<Long> msbs = loadedData.getLong("WorldUUIDMost");
Optional<Long> lsbs = loadedData.getLong("WorldUUIDLeast");
if (msbs.isPresent() && lsbs.isPresent()) {
// Modern Bukkit world.
bukkitWorld = Bukkit.getServer().getWorld(new UUID(msbs.get(), lsbs.get()));
} else {
bukkitWorld = loadedData.getString("world").map(Bukkit::getWorld).orElse(null);
}
if (bukkitWorld == null) {
spawnInDefaultWorld(server, player);
return;
}
player.setServerLevel(((CraftWorld) bukkitWorld).getHandle());
}
protected void spawnInDefaultWorld(MinecraftServer server, ServerPlayer player) {
ServerLevel level = server.getLevel(Level.OVERWORLD);
if (level != null) {
// Adjust player to default spawn (in keeping with Paper handling) when world not found.
LevelData.RespawnData respawnData = level.levelData.getRespawnData();
player.snapTo(player.adjustSpawnLocation(level, respawnData.pos()).getBottomCenter(), respawnData.yaw(), 0.0F);
player.spawnIn(level);
} else {
logger.warning("Tried to load player with invalid world when no fallback was available!");
}
}
protected void injectPlayer(MinecraftServer server, ServerPlayer player) throws IllegalAccessException {
if (bukkitEntity == null) {
return;
}
bukkitEntity.setAccessible(true);
bukkitEntity.set(player, new OpenPlayer(server.server, player, this));
return player.adjustSpawnLocation(level, respawnData.pos()).getBottomCenter();
}
@Override
public Player inject(Player player) {
try {
ServerPlayer nmsPlayer = getHandle(player);
if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) {
return openPlayer;
}
org.slf4j.Logger logger = LogUtils.getLogger();
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(nmsPlayer.problemPath(), logger)) {
CompoundTag extraData = new CompoundTag();
// Copy extra data out of existing player.
ValueOutput output = TagValueOutput.createWrappingWithContext(scopedCollector, nmsPlayer.registryAccess(), extraData);
nmsPlayer.getBukkitEntity().setExtraData(output);
MinecraftServer server = nmsPlayer.level().getServer();
injectPlayer(server, nmsPlayer);
CraftPlayer newPlayer = nmsPlayer.getBukkitEntity();
// Set extra data in new player.
ValueInput input = TagValueInput.create(scopedCollector, nmsPlayer.registryAccess(), extraData);
newPlayer.readExtraData(input);
return newPlayer;
}
} catch (IllegalAccessException e) {
logger.log(
java.util.logging.Level.WARNING,
e,
() -> "Unable to inject ServerPlayer, certain player data may be lost when saving!"
);
return player;
}
}
@Override
public @Nullable InventoryView openInventory(
Player bukkitPlayer,
ISpecialInventory inventory,
boolean viewOnly
) {
ServerPlayer player = getHandle(bukkitPlayer);
if (!OpenPlayer.isConnected(player.connection)) {
return null;
}
// See net.minecraft.server.level.ServerPlayer#openMenu(MenuProvider)
OpenChestMenu<?> menu;
Component title;
if (inventory instanceof BaseOpenInventory playerInv) {
menu = playerInv.createMenu(player, player.nextContainerCounter(), viewOnly);
title = playerInv.getTitle(player, menu);
} else if (inventory instanceof OpenEnderChest enderChest) {
menu = enderChest.createMenu(player, player.nextContainerCounter(), viewOnly);
title = enderChest.getTitle(menu);
} else {
return null;
}
// Should never happen, player is a ServerPlayer with an active connection.
if (menu == null) {
return null;
}
// Set up title. Title can only be set once for a menu, and is set during the open process.
// Further title changes are a hack where the client is sent a "new" inventory with the same ID,
// resulting in a title change but no other state modifications (like cursor position).
menu.setTitle(title);
var pair = CraftEventFactory.callInventoryOpenEventWithTitle(player, menu);
AbstractContainerMenu opened = pair.getSecond();
// Menu is null if event is cancelled.
if (opened == null) {
return null;
}
var newTitle = pair.getFirst();
if (newTitle != null) {
title = PaperAdventure.asVanilla(newTitle);
}
player.containerMenu = opened;
player.connection.send(new ClientboundOpenScreenPacket(opened.containerId, opened.getType(), title));
player.initMenu(opened);
return opened.getBukkitView();
protected void setServerLevel(ServerPlayer player, ServerLevel level) {
player.spawnIn(level);
}
}
+68
View File
@@ -0,0 +1,68 @@
import org.gradle.api.internal.attributes.DefaultCompatibilityRuleChain
plugins {
alias(libs.plugins.paperweight)
}
repositories {
maven("https://repo.papermc.io/repository/maven-public/")
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(25))
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
class ToolchainJvmVersion: AttributeCompatibilityRule<Int> {
override fun execute(details: CompatibilityCheckDetails<Int>) {
if (details.consumerValue == details.producerValue) {
details.compatible()
return
}
if (details.producerValue == null) {
details.incompatible()
return
}
if (25 >= details.producerValue!!) {
details.compatible()
} else {
details.incompatible()
}
}
}
dependencies {
attributesSchema {
attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE) {
// Gradle thinks that depending on a library with a certain language level requires
// any project that depends on it to also require that language level no matter what.
// This is a bit obnoxious when we're specifically adding compatiblity patches to shared common code.
// Realistically Gradle is correct and the chain should be reversed - the oldest, least common
// denominator should be targeted and patches should be slapped on top as necessary.
// However, I don't want to spend a week restructuring the project to cut a release.
// Hack out Gradle's rules and replace them with our own less-restrictive version.
val rules = compatibilityRules as DefaultCompatibilityRuleChain
rules.rules.clear()
compatibilityRules.add(ToolchainJvmVersion::class.java)
}
}
implementation(project(":openinvapi")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
implementation(project(":openinvcommon")) {
exclude(group = "org.spigotmc", module = "spigot-api")
}
paperweight.paperDevBundle("26.2.build.31-alpha")
}
tasks.reobfJar {
enabled = false
}
configurations.reobf.get().outgoing.artifacts.clear()
@@ -0,0 +1,95 @@
package com.lishid.openinv.internal.paper26_2;
import com.lishid.openinv.internal.Accessor;
import com.lishid.openinv.internal.IAnySilentContainer;
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.paper26_2.container.AnySilentContainer;
import com.lishid.openinv.internal.paper26_2.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_2.container.OpenInventory;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.PlaceholderLoader;
import com.lishid.openinv.internal.paper26_2.player.PlayerManager;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.world.Container;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.logging.Level;
import java.util.logging.Logger;
public class InternalAccessor implements Accessor {
protected final @NotNull Logger logger;
private final @NotNull PlayerManager manager;
private final @NotNull AnySilentContainer anySilentContainer;
public InternalAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
this.logger = logger;
manager = createPlayerManager(logger);
anySilentContainer = createAnySilentContainer(logger, lang);
}
protected @NotNull PlayerManager createPlayerManager(@NotNull Logger logger) {
return new PlayerManager(logger);
}
protected @NotNull AnySilentContainer createAnySilentContainer(
@NotNull Logger logger,
@NotNull LanguageManager lang
) {
return new AnySilentContainer(logger, lang);
}
protected @NotNull PlaceholderLoader createPlaceholderLoader() {
return new PlaceholderLoader();
}
@Override
public @NotNull PlayerManager getPlayerManager() {
return manager;
}
@Override
public @NotNull IAnySilentContainer getAnySilentContainer() {
return anySilentContainer;
}
@Override
public @NotNull ISpecialPlayerInventory createPlayerInventory(@NotNull Player player) {
return new OpenInventory(player);
}
@Override
public @NotNull ISpecialEnderChest createEnderChest(@NotNull Player player) {
return new OpenEnderChest(player);
}
@Override
public <T extends ISpecialInventory> @Nullable T get(@NotNull Inventory bukkitInventory, @NotNull Class<T> clazz) {
if (!(bukkitInventory instanceof CraftInventory craftInventory)) {
return null;
}
Container container = craftInventory.getInventory();
if (clazz.isInstance(container)) {
return clazz.cast(container);
}
return null;
}
@Override
public void reload(@NotNull ConfigurationSection config) {
ConfigurationSection placeholders = config.getConfigurationSection("placeholders");
try {
// Reset placeholders to defaults and try to load configuration.
createPlaceholderLoader().load(placeholders);
} catch (Exception e) {
logger.log(Level.WARNING, "Caught exception loading placeholder overrides!", e);
}
}
}
@@ -0,0 +1,232 @@
/*
* Copyright (C) 2011-2023 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.paper26_2.container;
import com.lishid.openinv.internal.AnySilentContainerBase;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_2.player.PlayerManager;
import com.lishid.openinv.util.ReflectionHelper;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.level.ServerPlayerGameMode;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.inventory.ChestMenu;
import net.minecraft.world.inventory.MenuType;
import net.minecraft.world.inventory.PlayerEnderChestContainer;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.block.BarrelBlock;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.ChestBlock;
import net.minecraft.world.level.block.ShulkerBoxBlock;
import net.minecraft.world.level.block.TrappedChestBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.EnderChestBlockEntity;
import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.bukkit.GameMode;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.logging.Logger;
public class AnySilentContainer extends AnySilentContainerBase {
private final @NotNull Logger logger;
private final @NotNull LanguageManager lang;
private @Nullable Field serverPlayerGameModeGameType;
public AnySilentContainer(@NotNull Logger logger, @NotNull LanguageManager lang) {
this.logger = logger;
this.lang = lang;
try {
try {
this.serverPlayerGameModeGameType = ServerPlayerGameMode.class.getDeclaredField("gameModeForPlayer");
this.serverPlayerGameModeGameType.setAccessible(true);
} catch (NoSuchFieldException e) {
logger.warning("The field ServerPlayerGameMode#gameModeForPlayer is no longer present!");
logger.warning("Please report this at https://github.com/Jikoo/OpenInv/issues");
logger.warning("Attempting to fall through using reflection. Please verify that SilentContainer does not fail.");
// N.B. gameModeForPlayer is (for now) declared before previousGameModeForPlayer so silent shouldn't break.
this.serverPlayerGameModeGameType = ReflectionHelper.grabFieldByType(ServerPlayerGameMode.class, GameType.class);
}
} catch (SecurityException e) {
logger.warning("Unable to directly write player game mode! SilentContainer will fail.");
logger.log(java.util.logging.Level.WARNING, "Error obtaining GameType field", e);
}
}
@Override
public boolean activateContainer(
@NotNull final Player bukkitPlayer,
final boolean silentchest,
@NotNull final org.bukkit.block.Block bukkitBlock
) {
// Silent ender chest is API-only
if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) {
bukkitPlayer.openInventory(bukkitPlayer.getEnderChest());
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true;
}
ServerPlayer player = PlayerManager.getHandle(bukkitPlayer);
final net.minecraft.world.level.Level level = ((Entity) player).level();
final BlockPos blockPos = new BlockPos(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());
final BlockEntity blockEntity = level.getBlockEntity(blockPos);
if (blockEntity == null) {
return false;
}
if (blockEntity instanceof EnderChestBlockEntity enderChestTile) {
// Anychest ender chest. See net.minecraft.world.level.block.EnderChestBlock
PlayerEnderChestContainer enderChest = player.getEnderChestInventory();
enderChest.setActiveChest(enderChestTile);
player.openMenu(
new SimpleMenuProvider(
(containerCounter, playerInventory, ignored) -> {
MenuType<?> containers = OpenChestMenu.getChestMenuType(enderChest.getContainerSize());
int rows = enderChest.getContainerSize() / 9;
return new ChestMenu(containers, containerCounter, playerInventory, enderChest, rows);
}, Component.translatable("container.enderchest")
)
);
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true;
}
if (!(blockEntity instanceof MenuProvider menuProvider)) {
return false;
}
BlockState blockState = level.getBlockState(blockPos);
Block block = blockState.getBlock();
if (block instanceof ChestBlock chestBlock) {
// boolean flag: do not check if chest is blocked
menuProvider = chestBlock.getMenuProvider(blockState, level, blockPos, true);
if (menuProvider == null) {
lang.sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false;
}
if (block instanceof TrappedChestBlock) {
bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED);
} else {
bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED);
}
}
if (block instanceof ShulkerBoxBlock) {
bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED);
}
if (block instanceof BarrelBlock) {
bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL);
}
// AnyChest only - SilentChest not active, container unsupported, or unnecessary.
if (!silentchest || player.gameMode.getGameModeForPlayer() == GameType.SPECTATOR) {
player.openMenu(menuProvider);
return true;
}
// SilentChest requires access to setting players' game mode directly.
if (this.serverPlayerGameModeGameType == null) {
return false;
}
if (blockEntity instanceof RandomizableContainerBlockEntity lootable) {
if (hasLootTable(lootable)) {
lang.sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false;
}
}
GameType gameType = player.gameMode.getGameModeForPlayer();
this.forceGameType(player, GameType.SPECTATOR);
player.openMenu(menuProvider);
this.forceGameType(player, gameType);
return true;
}
protected boolean hasLootTable(@NotNull RandomizableContainerBlockEntity lootable) {
return lootable.getLootTable() != null;
}
@Override
public void deactivateContainer(@NotNull final Player bukkitPlayer) {
if (this.serverPlayerGameModeGameType == null || bukkitPlayer.getGameMode() == GameMode.SPECTATOR) {
return;
}
ServerPlayer player = PlayerManager.getHandle(bukkitPlayer);
// Force game mode change without informing plugins or players.
// Regular game mode set calls GameModeChangeEvent and is cancellable.
GameType gameType = player.gameMode.getGameModeForPlayer();
this.forceGameType(player, GameType.SPECTATOR);
// ServerPlayer#closeContainer cannot be called without entering an
// infinite loop because this method is called during inventory close.
// From ServerPlayer#closeContainer -> CraftEventFactory#handleInventoryCloseEvent
player.containerMenu.transferTo(player.inventoryMenu, player.getBukkitEntity());
// From ServerPlayer#closeContainer
player.doCloseContainer();
// Regular inventory close will handle the rest - packet sending, etc.
// Revert forced game mode.
this.forceGameType(player, gameType);
}
private void forceGameType(final ServerPlayer player, final GameType gameMode) {
if (this.serverPlayerGameModeGameType == null) {
// No need to warn repeatedly, error on startup and lack of function should be enough.
return;
}
try {
this.serverPlayerGameModeGameType.setAccessible(true);
this.serverPlayerGameModeGameType.set(player.gameMode, gameMode);
} catch (IllegalArgumentException | IllegalAccessException e) {
logger.log(java.util.logging.Level.WARNING, "Error bypassing GameModeChangeEvent", e);
}
}
@Override
protected org.bukkit.block.BlockState getState(@NotNull org.bukkit.block.Block block) {
return block.getState(false);
}
@Override
protected InventoryHolder getHolder(@NotNull Inventory inventory) {
return inventory.getHolder(false);
}
}
@@ -1,22 +1,22 @@
package com.lishid.openinv.internal.paper26_1.container;
package com.lishid.openinv.internal.paper26_2.container;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.paper26_1.container.bukkit.OpenPlayerInventory;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_1.container.slot.Content;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentCrafting;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentCraftingResult;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentCursor;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentDrop;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentEquipment;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentList;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentOffHand;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentViewOnly;
import com.lishid.openinv.internal.paper26_1.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.player.PlayerManager;
import com.lishid.openinv.internal.paper26_2.container.bukkit.OpenPlayerInventory;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenInventoryMenu;
import com.lishid.openinv.internal.paper26_2.container.slot.Content;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentCrafting;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentCraftingResult;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentCursor;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentDrop;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentEquipment;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentList;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentOffHand;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentViewOnly;
import com.lishid.openinv.internal.paper26_2.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_2.player.PlayerManager;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component;
@@ -0,0 +1,205 @@
package com.lishid.openinv.internal.paper26_2.container;
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenEnderChestMenu;
import com.lishid.openinv.internal.paper26_2.player.PlayerManager;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.MutableComponent;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.player.StackedItemContents;
import net.minecraft.world.inventory.StackedContentsCompatible;
import net.minecraft.world.item.ItemStack;
import org.bukkit.Location;
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.inventory.CraftInventory;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.inventory.InventoryType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
public class OpenEnderChest implements Container, StackedContentsCompatible, InternalOwned<ServerPlayer>,
ISpecialEnderChest {
private CraftInventory inventory;
private @NotNull ServerPlayer owner;
private NonNullList<ItemStack> items;
private int maxStack = 64;
private final List<HumanEntity> transaction = new ArrayList<>();
public OpenEnderChest(@NotNull org.bukkit.entity.Player player) {
this.owner = PlayerManager.getHandle(player);
this.items = getEnderChestItems(owner);
}
@Override
public @NotNull ServerPlayer getOwnerHandle() {
return owner;
}
@Override
public @NotNull org.bukkit.inventory.Inventory getBukkitInventory() {
if (inventory == null) {
inventory = new CraftInventory(this) {
@Override
public @NotNull InventoryType getType() {
return InventoryType.ENDER_CHEST;
}
};
}
return inventory;
}
@Override
public void setPlayerOnline(@NotNull org.bukkit.entity.Player player) {
owner = PlayerManager.getHandle(player);
NonNullList<ItemStack> activeItems = getEnderChestItems(owner);
// Guard against size changing. Theoretically on Purpur all row variations still have 6 rows internally.
int max = Math.min(items.size(), activeItems.size());
for (int index = 0; index < max; ++index) {
activeItems.set(index, items.get(index));
}
items = activeItems;
}
protected @NotNull NonNullList<ItemStack> getEnderChestItems(@NotNull ServerPlayer owner) {
return owner.getEnderChestInventory().getItems();
}
@Override
public @NotNull org.bukkit.entity.Player getPlayer() {
return owner.getBukkitEntity();
}
@Override
public int getContainerSize() {
return items.size();
}
@Override
public boolean isEmpty() {
return items.stream().allMatch(ItemStack::isEmpty);
}
@Override
public @NotNull ItemStack getItem(int index) {
return index >= 0 && index < items.size() ? items.get(index) : ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack removeItem(int index, int amount) {
ItemStack itemstack = ContainerHelper.removeItem(items, index, amount);
if (!itemstack.isEmpty()) {
setChanged();
}
return itemstack;
}
@Override
public @NotNull ItemStack removeItemNoUpdate(int index) {
return index >= 0 && index < items.size() ? items.set(index, ItemStack.EMPTY) : ItemStack.EMPTY;
}
@Override
public void setItem(int index, @NotNull ItemStack itemStack) {
if (index >= 0 && index < items.size()) {
items.set(index, itemStack);
}
}
@Override
public int getMaxStackSize() {
return maxStack;
}
@Override
public void setChanged() {
this.owner.getEnderChestInventory().setChanged();
}
@Override
public boolean stillValid(@NotNull Player player) {
return true;
}
@Override
public @NotNull List<ItemStack> getContents() {
return items;
}
@Override
public void onOpen(@NotNull CraftHumanEntity craftHumanEntity) {
transaction.add(craftHumanEntity);
}
@Override
public void onClose(@NotNull CraftHumanEntity craftHumanEntity) {
transaction.remove(craftHumanEntity);
}
@Override
public @NotNull List<HumanEntity> getViewers() {
return transaction;
}
@Override
public org.bukkit.entity.Player getOwner() {
return getPlayer();
}
@Override
public void setMaxStackSize(int size) {
maxStack = size;
}
@Override
public @Nullable Location getLocation() {
return null;
}
@Override
public void clearContent() {
items.clear();
setChanged();
}
@Override
public void fillStackedContents(@NotNull StackedItemContents stackedContents) {
for (ItemStack itemstack : items) {
stackedContents.accountStack(itemstack);
}
}
public Component getTitle(@Nullable OpenChestMenu<?> menu) {
MutableComponent component;
if (menu != null && menu.isViewOnly()) {
component = Component.translatableWithFallback("openinv.container.enderchest.viewonly", "[RO] ");
} else {
component = Component.translatableWithFallback("openinv.container.enderchest.editable", "");
}
return component
.append(Component.translatableWithFallback("openinv.container.enderchest.prefix", "", owner.getName()))
.append(Component.translatable("container.enderchest"))
.append(Component.translatableWithFallback("openinv.container.enderchest.suffix", " - %s", owner.getName()));
}
public @Nullable OpenChestMenu<?> createMenu(Player player, int i, boolean viewOnly) {
if (player instanceof ServerPlayer serverPlayer) {
return new OpenEnderChestMenu(this, serverPlayer, i, viewOnly);
}
return null;
}
}
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container;
package com.lishid.openinv.internal.paper26_2.container;
import com.lishid.openinv.internal.paper26_1.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenChestMenu;
import net.minecraft.ChatFormatting;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.FontDescription;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.paper26_1.container.bukkit;
package com.lishid.openinv.internal.paper26_2.container.bukkit;
import com.lishid.openinv.internal.ViewOnly;
import net.minecraft.world.Container;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.paper26_1.container.bukkit;
package com.lishid.openinv.internal.paper26_2.container.bukkit;
import net.minecraft.world.Container;
import org.bukkit.Material;
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.paper26_1.container.bukkit;
package com.lishid.openinv.internal.paper26_2.container.bukkit;
import com.google.common.base.Preconditions;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_2.container.BaseOpenInventory;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Inventory;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container.bukkit;
package com.lishid.openinv.internal.paper26_2.container.bukkit;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_2.container.BaseOpenInventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -1,12 +1,12 @@
package com.lishid.openinv.internal.paper26_1.container.menu;
package com.lishid.openinv.internal.paper26_2.container.menu;
import com.google.common.base.Preconditions;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_1.container.bukkit.OpenDummyPlayerInventory;
import com.lishid.openinv.internal.paper26_1.container.bukkit.OpenPlayerInventorySelf;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentDrop;
import com.lishid.openinv.internal.paper26_1.container.slot.ContentEquipment;
import com.lishid.openinv.internal.paper26_1.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.paper26_2.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_2.container.bukkit.OpenDummyPlayerInventory;
import com.lishid.openinv.internal.paper26_2.container.bukkit.OpenPlayerInventorySelf;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentDrop;
import com.lishid.openinv.internal.paper26_2.container.slot.ContentEquipment;
import com.lishid.openinv.internal.paper26_2.container.slot.SlotViewOnly;
import com.lishid.openinv.util.Permissions;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EquipmentSlot;
@@ -1,9 +1,9 @@
package com.lishid.openinv.internal.paper26_1.container.menu;
package com.lishid.openinv.internal.paper26_2.container.menu;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.paper26_1.container.bukkit.OpenDummyInventory;
import com.lishid.openinv.internal.paper26_1.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.paper26_2.container.bukkit.OpenDummyInventory;
import com.lishid.openinv.internal.paper26_2.container.slot.SlotViewOnly;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container.menu;
package com.lishid.openinv.internal.paper26_2.container.menu;
import com.lishid.openinv.internal.paper26_1.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_2.container.OpenEnderChest;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ContainerInput;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container.menu;
package com.lishid.openinv.internal.paper26_2.container.menu;
import com.lishid.openinv.internal.paper26_1.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_2.container.BaseOpenInventory;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.ContainerInput;
@@ -1,9 +1,9 @@
package com.lishid.openinv.internal.paper26_1.container.menu;
package com.lishid.openinv.internal.paper26_2.container.menu;
import com.google.common.base.Suppliers;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.InternalOwned;
import com.lishid.openinv.internal.paper26_1.container.slot.SlotPlaceholder;
import com.lishid.openinv.internal.paper26_2.container.slot.SlotPlaceholder;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.AbstractContainerMenu;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_2.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.Placeholders;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.InventoryMenu;
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_2.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
@@ -1,7 +1,7 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_2.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.Slot;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.Placeholders;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.EntityEquipment;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import com.lishid.openinv.internal.paper26_2.player.OpenPlayer;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.Slot;
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container.slot;
package com.lishid.openinv.internal.paper26_2.container.slot;
import com.lishid.openinv.internal.paper26_1.container.slot.placeholder.Placeholders;
import com.lishid.openinv.internal.paper26_2.container.slot.placeholder.Placeholders;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
@@ -17,14 +17,14 @@ public class SlotViewOnly extends SlotPlaceholder {
public static @NotNull SlotViewOnly wrap(@NotNull Slot wrapped) {
SlotViewOnly wrapper;
if (wrapped instanceof SlotPlaceholder placeholder) {
wrapper = new SlotViewOnly(wrapped.container, wrapped.slot, wrapped.x, wrapped.y) {
wrapper = new SlotViewOnly(wrapped.container, wrapped.getContainerSlot(), wrapped.x, wrapped.y) {
@Override
public ItemStack getOrDefault() {
return placeholder.getOrDefault();
}
};
} else {
wrapper = new SlotViewOnly(wrapped.container, wrapped.slot, wrapped.x, wrapped.y) {
wrapper = new SlotViewOnly(wrapped.container, wrapped.getContainerSlot(), wrapped.x, wrapped.y) {
@Override
public ItemStack getOrDefault() {
return wrapped.getItem();
@@ -118,6 +118,11 @@ public class SlotViewOnly extends SlotPlaceholder {
return ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack safeClone(@NotNull Player player) {
return ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack safeInsert(@NotNull ItemStack itemStack) {
return itemStack;
@@ -133,11 +138,6 @@ public class SlotViewOnly extends SlotPlaceholder {
return false;
}
@Override
public int getContainerSlot() {
return this.slot;
}
@Override
public boolean isHighlightable() {
return false;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.paper26_1.container.slot.placeholder;
package com.lishid.openinv.internal.paper26_2.container.slot.placeholder;
import com.mojang.serialization.DataResult;
import net.minecraft.core.Registry;
@@ -7,11 +7,15 @@ import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.TagParser;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.Item;
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.item.component.TooltipDisplay;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.entity.BannerPattern;
@@ -22,9 +26,10 @@ import org.bukkit.craftbukkit.CraftRegistry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashSet;
import java.util.List;
public abstract class PlaceholderLoaderBase {
public class PlaceholderLoader {
public void load(@Nullable ConfigurationSection section) throws Exception {
Placeholders.craftingOutput = parse(section, "crafting-output", defaultCraftingOutput());
@@ -67,7 +72,7 @@ public abstract class PlaceholderLoaderBase {
return defaultStack;
}
CompoundTag compoundTag = parseTag(itemText);
CompoundTag compoundTag = TagParser.parseCompoundFully(itemText);
DataResult<ItemStack> parsed = ItemStack.CODEC.parse(CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE), compoundTag);
ItemStack itemStack;
try {
@@ -78,13 +83,16 @@ public abstract class PlaceholderLoaderBase {
return itemStack == null ? defaultStack : itemStack;
}
protected abstract @NotNull CompoundTag parseTag(@NotNull String itemText) throws Exception;
private static final CustomModelData DEFAULT_CUSTOM_MODEL_DATA = new CustomModelData(List.of(), List.of(), List.of("openinv:custom"), List.of());
private static final TooltipDisplay HIDE_TOOLTIP = new TooltipDisplay(true, new LinkedHashSet<>());
protected abstract void addModelData(@NotNull ItemStack itemStack);
protected void addModelData(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
}
protected abstract void hideTooltip(@NotNull ItemStack itemStack);
protected abstract DyedItemColor getDye(int rgb);
protected void hideTooltip(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.TOOLTIP_DISPLAY, HIDE_TOOLTIP);
}
protected @NotNull ItemStack defaultCraftingOutput() {
// Crafting table: "Crafting"
@@ -96,7 +104,7 @@ public abstract class PlaceholderLoaderBase {
protected @NotNull ItemStack defaultCursor() {
// Cursor-like banner with no tooltip
ItemStack itemStack = new ItemStack(Items.WHITE_BANNER);
ItemStack itemStack = new ItemStack(getDefaultCursorItem());
RegistryAccess minecraftRegistry = CraftRegistry.getMinecraftRegistry();
Registry<BannerPattern> bannerPatterns = minecraftRegistry.lookupOrThrow(Registries.BANNER_PATTERN);
BannerPattern halfDiagBottomRight = bannerPatterns.getOrThrow(BannerPatterns.DIAGONAL_RIGHT).value();
@@ -126,7 +134,7 @@ public abstract class PlaceholderLoaderBase {
protected @NotNull ItemStack getEmptyArmor(@NotNull ItemLike item) {
// Inventory-background-grey-ish leather armor with no tooltip
ItemStack itemStack = new ItemStack(item);
DyedItemColor color = getDye(0xC8C8C8);
DyedItemColor color = new DyedItemColor(0xC8C8C8);
itemStack.set(DataComponents.DYED_COLOR, color);
hideTooltip(itemStack);
addModelData(itemStack);
@@ -160,12 +168,20 @@ public abstract class PlaceholderLoaderBase {
protected @NotNull ItemStack defaultNotSlot() {
// White pane with no tooltip
ItemStack itemStack = new ItemStack(Items.WHITE_STAINED_GLASS_PANE);
ItemStack itemStack = new ItemStack(getDefaultNotSlotItem());
hideTooltip(itemStack);
addModelData(itemStack);
return itemStack;
}
protected @NotNull Item getDefaultCursorItem() {
return Items.BANNER.white();
}
protected @NotNull Item getDefaultNotSlotItem() {
return Items.STAINED_GLASS_PANE.white();
}
protected @NotNull ItemStack defaultBlockedOffline() {
// Barrier: "Not available - Offline"
ItemStack itemStack = new ItemStack(Items.BARRIER);
@@ -1,6 +1,6 @@
package com.lishid.openinv.internal.paper26_1.container.slot.placeholder;
package com.lishid.openinv.internal.paper26_2.container.slot.placeholder;
import com.lishid.openinv.internal.paper26_1.player.OpenPlayer;
import com.lishid.openinv.internal.paper26_2.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameType;
@@ -10,6 +10,10 @@ import java.util.EnumMap;
public final class Placeholders {
// N.B. Slot#getNoItemIcon is still clientside, unfortunately.
// Worth checking every few updates just in case - it would be nice to
// get rid of some of the placeholders.
static final @NotNull EnumMap<GameType, ItemStack> BLOCKED_GAME_TYPE = new EnumMap<>(GameType.class);
public static @NotNull ItemStack craftingOutput = ItemStack.EMPTY;
public static @NotNull ItemStack cursor = ItemStack.EMPTY;
@@ -1,4 +1,4 @@
package com.lishid.openinv.internal.paper26_1.player;
package com.lishid.openinv.internal.paper26_2.player;
import com.lishid.openinv.event.OpenEvents;
import com.mojang.logging.LogUtils;
@@ -23,7 +23,6 @@ import org.slf4j.Logger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;
import java.util.Set;
public class OpenPlayer extends CraftPlayer {
@@ -54,6 +53,7 @@ public class OpenPlayer extends CraftPlayer {
// Intentional omissions to prevent mount loss: Attach, Entity, and RootVehicle
"warden_spawn_tracker", // No longer needed as of 1.21.11
"entered_nether_pos",
"last_explosion_impact_pos",
"respawn",
"raid_omen_position",
"ender_pearls",
@@ -98,9 +98,8 @@ public class OpenPlayer extends CraftPlayer {
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), logger)) {
PlayerDataStorage worldNbtStorage = server.getServer().getPlayerList().playerIo;
CompoundTag oldData = isOnline()
? null
: load(worldNbtStorage, player, scopedCollector).orElse(null);
CompoundTag oldData;
oldData = isOnline() ? null : worldNbtStorage.load(player.nameAndId()).orElse(null);
CompoundTag playerData = getWritableTag(oldData);
ValueOutput valueOutput = TagValueOutput.createWrappingWithContext(scopedCollector, player.registryAccess(), playerData);
@@ -112,14 +111,6 @@ public class OpenPlayer extends CraftPlayer {
}
}
protected Optional<CompoundTag> load(
PlayerDataStorage storage,
ServerPlayer player,
ProblemReporter.ScopedCollector collector
) {
return storage.load(player.nameAndId());
}
protected void saveSafe(
@NotNull ServerPlayer player,
@Nullable CompoundTag oldData,
@@ -0,0 +1,330 @@
package com.lishid.openinv.internal.paper26_2.player;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.paper26_2.container.BaseOpenInventory;
import com.lishid.openinv.internal.paper26_2.container.OpenEnderChest;
import com.lishid.openinv.internal.paper26_2.container.menu.OpenChestMenu;
import com.lishid.openinv.util.JulLoggerAdapter;
import com.mojang.authlib.GameProfile;
import com.mojang.logging.LogUtils;
import io.papermc.paper.adventure.PaperAdventure;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ClientInformation;
import net.minecraft.server.level.ParticleStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.ChatVisiblity;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.LevelData;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.Vec3;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.entity.CraftPlayer;
import org.bukkit.craftbukkit.event.CraftEventFactory;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryView;
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.Optional;
import java.util.UUID;
import java.util.logging.Logger;
@NullMarked
public class PlayerManager implements com.lishid.openinv.internal.PlayerManager {
protected final Logger logger;
protected @Nullable Field bukkitEntity;
public PlayerManager(Logger logger) {
this.logger = logger;
try {
bukkitEntity = Entity.class.getDeclaredField("bukkitEntity");
} catch (NoSuchFieldException e) {
logger.warning("Unable to obtain field to inject custom save process - certain player data may be lost when saving!");
logger.log(java.util.logging.Level.WARNING, e.getMessage(), e);
bukkitEntity = null;
}
}
public static ServerPlayer getHandle(final Player player) {
if (player instanceof CraftPlayer craftPlayer) {
return craftPlayer.getHandle();
}
Server server = player.getServer();
ServerPlayer nmsPlayer = null;
if (server instanceof CraftServer craftServer) {
nmsPlayer = craftServer.getHandle().getPlayer(player.getUniqueId());
}
if (nmsPlayer == null) {
// Could use reflection to examine fields, but it's honestly not worth the bother.
throw new RuntimeException("Unable to fetch EntityPlayer from Player implementation " + player.getClass().getName());
}
return nmsPlayer;
}
@Override
public @Nullable Player loadPlayer(final OfflinePlayer offline) {
if (!(Bukkit.getServer() instanceof CraftServer craftServer)) {
return null;
}
MinecraftServer server = craftServer.getServer();
ServerLevel worldServer = server.getLevel(Level.OVERWORLD);
if (worldServer == null) {
return null;
}
// Create a new ServerPlayer.
ServerPlayer entity = createNewPlayer(server, worldServer, offline);
// Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak.
removeAdvancementListeners(entity);
// Try to load the player's data.
if (loadData(server, entity)) {
// If data is loaded successfully, return the Bukkit entity.
return entity.getBukkitEntity();
}
return null;
}
protected ServerPlayer createNewPlayer(
MinecraftServer server,
ServerLevel worldServer,
final OfflinePlayer offline
) {
// See net.minecraft.server.players.PlayerList#canPlayerLogin(ServerLoginPacketListenerImpl, GameProfile)
// See net.minecraft.server.network.ServerLoginPacketListenerImpl#handleHello(ServerboundHelloPacket)
GameProfile profile = new GameProfile(offline.getUniqueId(),
offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()
);
ClientInformation dummyInfo = new ClientInformation(
"en_us",
1, // Reduce distance just in case.
ChatVisiblity.HIDDEN, // Don't accept chat.
false,
ServerPlayer.DEFAULT_MODEL_CUSTOMIZATION,
ServerPlayer.DEFAULT_MAIN_HAND,
true,
false, // Don't list in player list (not that this player is in the list anyway).
ParticleStatus.MINIMAL
);
ServerPlayer entity = new ServerPlayer(server, worldServer, profile, dummyInfo);
try {
injectPlayer(server, entity);
} catch (IllegalAccessException e) {
logger.log(
java.util.logging.Level.WARNING,
e,
() -> "Unable to inject ServerPlayer, certain player data may be lost when saving!"
);
}
return entity;
}
protected void removeAdvancementListeners(ServerPlayer entity) {
entity.getAdvancements().clearTriggers();
}
protected boolean loadData(MinecraftServer server, ServerPlayer player) {
// See CraftPlayer#loadData
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), new JulLoggerAdapter(logger))) {
CompoundTag loadedData = server.getPlayerList().playerIo.load(player.nameAndId()).orElse(null);
if (loadedData == null) {
// Exceptions with loading are logged.
return false;
}
ValueInput valueInput = TagValueInput.create(scopedCollector, player.registryAccess(), loadedData);
// Read basic data into the player.
player.load(valueInput);
// World is not loaded by ServerPlayer#load(CompoundTag) on Paper.
parseWorld(server, player, valueInput);
}
return true;
}
protected void parseWorld(
MinecraftServer server,
ServerPlayer player,
ValueInput loadedData
) {
// See PlayerList#placeNewPlayer
World bukkitWorld;
Optional<Long> msbs = loadedData.getLong("WorldUUIDMost");
Optional<Long> lsbs = loadedData.getLong("WorldUUIDLeast");
if (msbs.isPresent() && lsbs.isPresent()) {
// Modern Bukkit world.
bukkitWorld = Bukkit.getServer().getWorld(new UUID(msbs.get(), lsbs.get()));
} else {
bukkitWorld = loadedData.getString("world").map(Bukkit::getWorld).orElse(null);
}
if (bukkitWorld == null) {
spawnInDefaultWorld(server, player);
return;
}
player.setServerLevel(((CraftWorld) bukkitWorld).getHandle());
}
protected void spawnInDefaultWorld(MinecraftServer server, ServerPlayer player) {
ServerLevel level = server.getLevel(Level.OVERWORLD);
if (level != null) {
// Adjust player to default spawn (in keeping with Paper handling) when world not found.
LevelData.RespawnData respawnData = getRespawnData(level);
player.snapTo(getAdjustedSpawnLocation(player, level, respawnData), respawnData.yaw(), 0.0F);
setServerLevel(player, level);
} else {
logger.warning("Tried to load player with invalid world when no fallback was available!");
}
}
protected LevelData.RespawnData getRespawnData(ServerLevel level) {
return level.getRespawnData();
}
protected Vec3 getAdjustedSpawnLocation(
ServerPlayer player,
ServerLevel level,
LevelData.RespawnData respawnData
) {
return Vec3.atBottomCenterOf(player.adjustSpawnLocation(level, respawnData.pos()));
}
protected void setServerLevel(ServerPlayer player, ServerLevel level) {
player.setServerLevel(level);
}
protected void injectPlayer(MinecraftServer server, ServerPlayer player) throws IllegalAccessException {
if (bukkitEntity == null) {
return;
}
bukkitEntity.setAccessible(true);
bukkitEntity.set(player, new OpenPlayer(server.server, player, this));
}
@Override
public Player inject(Player player) {
try {
ServerPlayer nmsPlayer = getHandle(player);
if (nmsPlayer.getBukkitEntity() instanceof OpenPlayer openPlayer) {
return openPlayer;
}
org.slf4j.Logger logger = LogUtils.getLogger();
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(nmsPlayer.problemPath(), logger)) {
CompoundTag extraData = new CompoundTag();
// Copy extra data out of existing player.
ValueOutput output = TagValueOutput.createWrappingWithContext(scopedCollector, nmsPlayer.registryAccess(), extraData);
nmsPlayer.getBukkitEntity().setExtraData(output);
MinecraftServer server = nmsPlayer.level().getServer();
injectPlayer(server, nmsPlayer);
CraftPlayer newPlayer = nmsPlayer.getBukkitEntity();
// Set extra data in new player.
ValueInput input = TagValueInput.create(scopedCollector, nmsPlayer.registryAccess(), extraData);
newPlayer.readExtraData(input);
return newPlayer;
}
} catch (IllegalAccessException e) {
logger.log(
java.util.logging.Level.WARNING,
e,
() -> "Unable to inject ServerPlayer, certain player data may be lost when saving!"
);
return player;
}
}
@Override
public @Nullable InventoryView openInventory(
Player bukkitPlayer,
ISpecialInventory inventory,
boolean viewOnly
) {
ServerPlayer player = getHandle(bukkitPlayer);
if (!OpenPlayer.isConnected(player.connection)) {
return null;
}
// See net.minecraft.server.level.ServerPlayer#openMenu(MenuProvider)
OpenChestMenu<?> menu;
Component title;
if (inventory instanceof BaseOpenInventory playerInv) {
menu = playerInv.createMenu(player, player.nextContainerCounter(), viewOnly);
title = playerInv.getTitle(player, menu);
} else if (inventory instanceof OpenEnderChest enderChest) {
menu = enderChest.createMenu(player, player.nextContainerCounter(), viewOnly);
title = enderChest.getTitle(menu);
} else {
return null;
}
// Should never happen, player is a ServerPlayer with an active connection.
if (menu == null) {
return null;
}
// Set up title. Title can only be set once for a menu, and is set during the open process.
// Further title changes are a hack where the client is sent a "new" inventory with the same ID,
// resulting in a title change but no other state modifications (like cursor position).
menu.setTitle(title);
var pair = CraftEventFactory.callInventoryOpenEventWithTitle(player, menu);
AbstractContainerMenu opened = pair.getSecond();
// Menu is null if event is cancelled.
if (opened == null) {
return null;
}
var newTitle = pair.getFirst();
if (newTitle != null) {
title = PaperAdventure.asVanilla(newTitle);
}
player.containerMenu = opened;
player.connection.send(new ClientboundOpenScreenPacket(opened.containerId, opened.getType(), title));
player.initMenu(opened);
return opened.getBukkitView();
}
}
@@ -1,40 +0,0 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.TagParser;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.component.CustomModelData;
import net.minecraft.world.item.component.DyedItemColor;
import net.minecraft.world.item.component.TooltipDisplay;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashSet;
import java.util.List;
public class PlaceholderLoader extends PlaceholderLoaderBase {
private static final CustomModelData DEFAULT_CUSTOM_MODEL_DATA = new CustomModelData(List.of(), List.of(), List.of("openinv:custom"), List.of());
private static final TooltipDisplay HIDE_TOOLTIP = new TooltipDisplay(true, new LinkedHashSet<>());
@Override
protected @NotNull CompoundTag parseTag(@NotNull String itemText) throws Exception {
return TagParser.parseCompoundFully(itemText);
}
@Override
protected void addModelData(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
}
@Override
protected void hideTooltip(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.TOOLTIP_DISPLAY, HIDE_TOOLTIP);
}
@Override
protected DyedItemColor getDye(int rgb) {
return new DyedItemColor(rgb);
}
}
+36
View File
@@ -0,0 +1,36 @@
import com.github.jikoo.openinv.SpigotDependencyExtension
import com.github.jikoo.openinv.SpigotSetup
plugins {
alias(libs.plugins.shadow)
}
repositories {
maven("https://repo.papermc.io/repository/maven-public/")
}
java {
toolchain.languageVersion = JavaLanguageVersion.of(25)
}
tasks.withType<JavaCompile>().configureEach {
options.release = 21
}
apply<SpigotSetup>()
dependencies {
compileOnly(libs.spigotapi)
extensions.getByType(SpigotDependencyExtension::class.java).version = "26.1.2-R0.1-SNAPSHOT"
compileOnly("com.mojang:logging:1.6.11")
compileOnly("com.mojang:brigadier:1.3.10")
compileOnly("com.mojang:datafixerupper:9.0.19")
compileOnly("com.mojang:authlib:7.0.62")
compileOnly(project(":openinvapi"))
compileOnly(project(":openinvcommon"))
compileOnly(project(":openinvadapterspigot26_2")) {
exclude(group = "org.spigotmc", module = "spigot")
}
}
@@ -0,0 +1,38 @@
package com.github.jikoo.openinv.internal.spigot26_1;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.PlaceholderLoader;
import com.github.jikoo.openinv.internal.spigot26_1.player.PlayerManager;
import com.lishid.openinv.util.lang.LanguageManager;
import org.bukkit.configuration.ConfigurationSection;
import org.jspecify.annotations.NullMarked;
import java.util.logging.Level;
import java.util.logging.Logger;
@NullMarked
public class InternalAccessor extends com.github.jikoo.openinv.internal.spigot26_2.InternalAccessor {
private final PlayerManager manager;
public InternalAccessor(Logger logger, LanguageManager lang) {
super(logger, lang);
this.manager = new PlayerManager(logger);
}
@Override
public PlayerManager getPlayerManager() {
return manager;
}
@Override
public void reload(ConfigurationSection config) {
ConfigurationSection placeholders = config.getConfigurationSection("placeholders");
try {
// Reset placeholders to defaults and try to load configuration.
new PlaceholderLoader().load(placeholders);
} catch (Exception e) {
logger.log(Level.WARNING, "Caught exception loading placeholder overrides!", e);
}
}
}
@@ -0,0 +1,21 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.PlaceholderLoaderBase;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import org.jspecify.annotations.NullMarked;
@NullMarked
public class PlaceholderLoader extends PlaceholderLoaderBase {
@Override
protected Item getWhiteBanner() {
return Items.WHITE_BANNER;
}
@Override
protected Item getWhiteGlassPane() {
return Items.WHITE_STAINED_GLASS_PANE;
}
}
@@ -0,0 +1,20 @@
package com.github.jikoo.openinv.internal.spigot26_1.player;
import net.minecraft.server.PlayerAdvancements;
import org.jspecify.annotations.NullMarked;
import java.util.logging.Logger;
@NullMarked
public class PlayerManager extends com.github.jikoo.openinv.internal.spigot26_2.player.PlayerManager {
public PlayerManager(Logger logger) {
super(logger);
}
@Override
protected void removeListeners(PlayerAdvancements advancements) {
advancements.stopListening();
}
}
@@ -21,7 +21,7 @@ apply<SpigotSetup>()
dependencies {
compileOnly(libs.spigotapi)
extensions.getByType(SpigotDependencyExtension::class.java).version = "26.1.2-R0.1-SNAPSHOT"
extensions.getByType(SpigotDependencyExtension::class.java).version = "26.2-R0.1-SNAPSHOT"
compileOnly("com.mojang:logging:1.6.11")
compileOnly("com.mojang:brigadier:1.3.10")
compileOnly("com.mojang:datafixerupper:9.0.19")
@@ -1,10 +1,10 @@
package com.github.jikoo.openinv.internal.spigot26_1;
package com.github.jikoo.openinv.internal.spigot26_2;
import com.github.jikoo.openinv.internal.spigot26_1.container.AnySilentContainer;
import com.github.jikoo.openinv.internal.spigot26_1.container.OpenInventory;
import com.github.jikoo.openinv.internal.spigot26_1.container.OpenEnderChest;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.PlaceholderLoader;
import com.github.jikoo.openinv.internal.spigot26_1.player.PlayerManager;
import com.github.jikoo.openinv.internal.spigot26_2.container.AnySilentContainer;
import com.github.jikoo.openinv.internal.spigot26_2.container.OpenInventory;
import com.github.jikoo.openinv.internal.spigot26_2.container.OpenEnderChest;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.PlaceholderLoader;
import com.github.jikoo.openinv.internal.spigot26_2.player.PlayerManager;
import com.lishid.openinv.internal.Accessor;
import com.lishid.openinv.internal.IAnySilentContainer;
import com.lishid.openinv.internal.ISpecialEnderChest;
@@ -1,8 +1,8 @@
package com.github.jikoo.openinv.internal.spigot26_1.container;
package com.github.jikoo.openinv.internal.spigot26_2.container;
import com.lishid.openinv.internal.AnySilentContainerBase;
import com.github.jikoo.openinv.internal.spigot26_1.container.menu.OpenChestMenu;
import com.github.jikoo.openinv.internal.spigot26_1.player.PlayerManager;
import com.github.jikoo.openinv.internal.spigot26_2.container.menu.OpenChestMenu;
import com.github.jikoo.openinv.internal.spigot26_2.player.PlayerManager;
import com.lishid.openinv.util.ReflectionHelper;
import com.lishid.openinv.util.lang.LanguageManager;
import net.minecraft.core.BlockPos;
@@ -1,8 +1,8 @@
package com.github.jikoo.openinv.internal.spigot26_1.container;
package com.github.jikoo.openinv.internal.spigot26_2.container;
import com.github.jikoo.openinv.internal.spigot26_1.container.menu.OpenChestMenu;
import com.github.jikoo.openinv.internal.spigot26_1.container.menu.OpenEnderChestMenu;
import com.github.jikoo.openinv.internal.spigot26_1.player.PlayerManager;
import com.github.jikoo.openinv.internal.spigot26_2.container.menu.OpenChestMenu;
import com.github.jikoo.openinv.internal.spigot26_2.container.menu.OpenEnderChestMenu;
import com.github.jikoo.openinv.internal.spigot26_2.player.PlayerManager;
import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.InternalOwned;
import net.minecraft.core.NonNullList;
@@ -1,20 +1,20 @@
package com.github.jikoo.openinv.internal.spigot26_1.container;
package com.github.jikoo.openinv.internal.spigot26_2.container;
import com.github.jikoo.openinv.internal.spigot26_1.container.bukkit.OpenPlayerInventory;
import com.github.jikoo.openinv.internal.spigot26_1.container.menu.OpenChestMenu;
import com.github.jikoo.openinv.internal.spigot26_1.container.menu.OpenInventoryMenu;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.Content;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentCrafting;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentCraftingResult;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentCursor;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentDrop;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentEquipment;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentList;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentOffHand;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentViewOnly;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.SlotViewOnly;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_1.player.PlayerManager;
import com.github.jikoo.openinv.internal.spigot26_2.container.bukkit.OpenPlayerInventory;
import com.github.jikoo.openinv.internal.spigot26_2.container.menu.OpenChestMenu;
import com.github.jikoo.openinv.internal.spigot26_2.container.menu.OpenInventoryMenu;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.Content;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentCrafting;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentCraftingResult;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentCursor;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentDrop;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentEquipment;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentList;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentOffHand;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentViewOnly;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.SlotViewOnly;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_2.player.PlayerManager;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.internal.InternalOwned;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
@@ -1,4 +1,4 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.bukkit;
package com.github.jikoo.openinv.internal.spigot26_2.container.bukkit;
import com.lishid.openinv.internal.ViewOnly;
import net.minecraft.world.Container;
@@ -40,16 +40,19 @@ public class OpenDummyInventory extends CraftInventory implements ViewOnly {
}
@SuppressWarnings("NonApiType")
@Override
public @NotNull HashMap<Integer, ItemStack> addItem(@NotNull ItemStack... items) throws IllegalArgumentException {
return arrayToHashMap(items);
}
@SuppressWarnings("NonApiType")
@Override
public @NotNull HashMap<Integer, ItemStack> removeItem(@NotNull ItemStack... items) throws IllegalArgumentException {
return arrayToHashMap(items);
}
@SuppressWarnings("NonApiType")
private static @NotNull HashMap<Integer, ItemStack> arrayToHashMap(@NotNull ItemStack[] items) {
HashMap<Integer, ItemStack> ignored = new HashMap<>();
for (int index = 0; index < items.length; ++index) {
@@ -103,6 +106,7 @@ public class OpenDummyInventory extends CraftInventory implements ViewOnly {
return false;
}
@SuppressWarnings("NonApiType")
@Override
public @NotNull HashMap<Integer, ItemStack> all(
@NotNull Material material
@@ -110,6 +114,7 @@ public class OpenDummyInventory extends CraftInventory implements ViewOnly {
return new HashMap<>();
}
@SuppressWarnings("NonApiType")
@Override
public @NotNull HashMap<Integer, ItemStack> all(@Nullable ItemStack item) {
return new HashMap<>();
@@ -1,4 +1,4 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.bukkit;
package com.github.jikoo.openinv.internal.spigot26_2.container.bukkit;
import net.minecraft.world.Container;
import org.bukkit.Material;
@@ -1,7 +1,7 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.bukkit;
package com.github.jikoo.openinv.internal.spigot26_2.container.bukkit;
import com.google.common.base.Preconditions;
import com.github.jikoo.openinv.internal.spigot26_1.container.OpenInventory;
import com.github.jikoo.openinv.internal.spigot26_2.container.OpenInventory;
import net.minecraft.core.NonNullList;
import net.minecraft.world.entity.player.Inventory;
import org.bukkit.craftbukkit.inventory.CraftInventory;
@@ -1,6 +1,6 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.bukkit;
package com.github.jikoo.openinv.internal.spigot26_2.container.bukkit;
import com.github.jikoo.openinv.internal.spigot26_1.container.OpenInventory;
import com.github.jikoo.openinv.internal.spigot26_2.container.OpenInventory;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
@@ -1,7 +1,7 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.menu;
package com.github.jikoo.openinv.internal.spigot26_2.container.menu;
import com.github.jikoo.openinv.internal.spigot26_1.container.bukkit.OpenDummyInventory;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.SlotViewOnly;
import com.github.jikoo.openinv.internal.spigot26_2.container.bukkit.OpenDummyInventory;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.SlotViewOnly;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.InternalOwned;
import net.minecraft.server.level.ServerPlayer;
@@ -1,6 +1,6 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.menu;
package com.github.jikoo.openinv.internal.spigot26_2.container.menu;
import com.github.jikoo.openinv.internal.spigot26_1.container.OpenEnderChest;
import com.github.jikoo.openinv.internal.spigot26_2.container.OpenEnderChest;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
@@ -1,13 +1,13 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.menu;
package com.github.jikoo.openinv.internal.spigot26_2.container.menu;
import com.google.common.base.Preconditions;
import com.lishid.openinv.util.Permissions;
import com.github.jikoo.openinv.internal.spigot26_1.container.OpenInventory;
import com.github.jikoo.openinv.internal.spigot26_1.container.bukkit.OpenDummyPlayerInventory;
import com.github.jikoo.openinv.internal.spigot26_1.container.bukkit.OpenPlayerInventorySelf;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentDrop;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.ContentEquipment;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.SlotViewOnly;
import com.github.jikoo.openinv.internal.spigot26_2.container.OpenInventory;
import com.github.jikoo.openinv.internal.spigot26_2.container.bukkit.OpenDummyPlayerInventory;
import com.github.jikoo.openinv.internal.spigot26_2.container.bukkit.OpenPlayerInventorySelf;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentDrop;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.ContentEquipment;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.SlotViewOnly;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.entity.EquipmentSlot;
import net.minecraft.world.entity.player.Player;
@@ -1,9 +1,9 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.menu;
package com.github.jikoo.openinv.internal.spigot26_2.container.menu;
import com.google.common.base.Suppliers;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.InternalOwned;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.SlotPlaceholder;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.SlotPlaceholder;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import net.minecraft.network.HashedStack;
@@ -1,4 +1,4 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,7 +1,7 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_1.player.OpenPlayer;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_2.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
@@ -1,6 +1,6 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.Placeholders;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.InventoryMenu;
@@ -1,7 +1,7 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_1.player.OpenPlayer;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_2.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
@@ -1,7 +1,7 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_1.player.OpenPlayer;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_2.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.Slot;
@@ -1,6 +1,6 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.Placeholders;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
import net.minecraft.world.entity.EquipmentSlot;
@@ -1,4 +1,4 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,6 +1,6 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import com.github.jikoo.openinv.internal.spigot26_1.player.OpenPlayer;
import com.github.jikoo.openinv.internal.spigot26_2.player.OpenPlayer;
import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,4 +1,4 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.Container;
@@ -1,4 +1,4 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import net.minecraft.world.Container;
import net.minecraft.world.inventory.Slot;
@@ -1,6 +1,6 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot;
import com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder.Placeholders;
import com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder.Placeholders;
import net.minecraft.world.Container;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.Slot;
@@ -118,6 +118,11 @@ public class SlotViewOnly extends SlotPlaceholder {
return ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack safeClone(@NotNull Player player) {
return ItemStack.EMPTY;
}
@Override
public @NotNull ItemStack safeInsert(@NotNull ItemStack itemStack) {
return itemStack;
@@ -133,11 +138,6 @@ public class SlotViewOnly extends SlotPlaceholder {
return false;
}
@Override
public int getContainerSlot() {
return this.slot;
}
@Override
public boolean isHighlightable() {
return false;
@@ -0,0 +1,19 @@
package com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
public class PlaceholderLoader extends PlaceholderLoaderBase {
@Override
protected @NotNull Item getWhiteBanner() {
return Items.BANNER.white();
}
@Override
protected @NotNull Item getWhiteGlassPane() {
return Items.STAINED_GLASS_PANE.white();
}
}
@@ -1,4 +1,4 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder;
import com.mojang.serialization.DataResult;
import net.minecraft.core.Registry;
@@ -7,11 +7,15 @@ import net.minecraft.core.component.DataComponents;
import net.minecraft.core.registries.Registries;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.nbt.TagParser;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.DyeColor;
import net.minecraft.world.item.Item;
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.item.component.TooltipDisplay;
import net.minecraft.world.level.GameType;
import net.minecraft.world.level.ItemLike;
import net.minecraft.world.level.block.entity.BannerPattern;
@@ -22,10 +26,14 @@ import org.bukkit.craftbukkit.CraftRegistry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.LinkedHashSet;
import java.util.List;
public abstract class PlaceholderLoaderBase {
private static final CustomModelData DEFAULT_CUSTOM_MODEL_DATA = new CustomModelData(List.of(), List.of(), List.of("openinv:custom"), List.of());
private static final TooltipDisplay HIDE_TOOLTIP = new TooltipDisplay(true, new LinkedHashSet<>());
public void load(@Nullable ConfigurationSection section) throws Exception {
Placeholders.craftingOutput = parse(section, "crafting-output", defaultCraftingOutput());
Placeholders.cursor = parse(section, "cursor", defaultCursor());
@@ -67,7 +75,7 @@ public abstract class PlaceholderLoaderBase {
return defaultStack;
}
CompoundTag compoundTag = parseTag(itemText);
CompoundTag compoundTag = TagParser.parseCompoundFully(itemText);
DataResult<ItemStack> parsed = ItemStack.CODEC.parse(CraftRegistry.getMinecraftRegistry().createSerializationContext(NbtOps.INSTANCE), compoundTag);
ItemStack itemStack;
try {
@@ -78,13 +86,13 @@ public abstract class PlaceholderLoaderBase {
return itemStack == null ? defaultStack : itemStack;
}
protected abstract @NotNull CompoundTag parseTag(@NotNull String itemText) throws Exception;
protected void addModelData(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.CUSTOM_MODEL_DATA, DEFAULT_CUSTOM_MODEL_DATA);
}
protected abstract void addModelData(@NotNull ItemStack itemStack);
protected abstract void hideTooltip(@NotNull ItemStack itemStack);
protected abstract DyedItemColor getDye(int rgb);
protected void hideTooltip(@NotNull ItemStack itemStack) {
itemStack.set(DataComponents.TOOLTIP_DISPLAY, HIDE_TOOLTIP);
}
protected @NotNull ItemStack defaultCraftingOutput() {
// Crafting table: "Crafting"
@@ -96,7 +104,7 @@ public abstract class PlaceholderLoaderBase {
protected @NotNull ItemStack defaultCursor() {
// Cursor-like banner with no tooltip
ItemStack itemStack = new ItemStack(Items.WHITE_BANNER);
ItemStack itemStack = new ItemStack(getWhiteBanner());
RegistryAccess minecraftRegistry = CraftRegistry.getMinecraftRegistry();
Registry<BannerPattern> bannerPatterns = minecraftRegistry.lookupOrThrow(Registries.BANNER_PATTERN);
BannerPattern halfDiagBottomRight = bannerPatterns.getOrThrow(BannerPatterns.DIAGONAL_RIGHT).value();
@@ -114,6 +122,8 @@ public abstract class PlaceholderLoaderBase {
return itemStack;
}
protected abstract @NotNull Item getWhiteBanner();
protected @NotNull ItemStack defaultDrop() {
// Dropper: "Drop Selected Item"
ItemStack itemStack = new ItemStack(Items.DROPPER);
@@ -126,7 +136,7 @@ public abstract class PlaceholderLoaderBase {
protected @NotNull ItemStack getEmptyArmor(@NotNull ItemLike item) {
// Inventory-background-grey-ish leather armor with no tooltip
ItemStack itemStack = new ItemStack(item);
DyedItemColor color = getDye(0xC8C8C8);
DyedItemColor color = new DyedItemColor(0xC8C8C8);
itemStack.set(DataComponents.DYED_COLOR, color);
hideTooltip(itemStack);
addModelData(itemStack);
@@ -160,12 +170,14 @@ public abstract class PlaceholderLoaderBase {
protected @NotNull ItemStack defaultNotSlot() {
// White pane with no tooltip
ItemStack itemStack = new ItemStack(Items.WHITE_STAINED_GLASS_PANE);
ItemStack itemStack = new ItemStack(getWhiteGlassPane());
hideTooltip(itemStack);
addModelData(itemStack);
return itemStack;
}
protected abstract @NotNull Item getWhiteGlassPane();
protected @NotNull ItemStack defaultBlockedOffline() {
// Barrier: "Not available - Offline"
ItemStack itemStack = new ItemStack(Items.BARRIER);
@@ -1,6 +1,6 @@
package com.github.jikoo.openinv.internal.spigot26_1.container.slot.placeholder;
package com.github.jikoo.openinv.internal.spigot26_2.container.slot.placeholder;
import com.github.jikoo.openinv.internal.spigot26_1.player.OpenPlayer;
import com.github.jikoo.openinv.internal.spigot26_2.player.OpenPlayer;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.GameType;
@@ -1,4 +1,4 @@
package com.github.jikoo.openinv.internal.spigot26_1.player;
package com.github.jikoo.openinv.internal.spigot26_2.player;
import com.lishid.openinv.event.OpenEvents;
import com.mojang.logging.LogUtils;
@@ -31,7 +31,7 @@ public class OpenPlayer extends CraftPlayer {
/**
* List of tags to always reset when saving.
*
* @see net.minecraft.world.entity.Entity#saveWithoutId(ValueOutput)
* @see net.minecraft.world.entity.Entity#saveWithoutId(ValueOutput, boolean)
* @see ServerPlayer#addAdditionalSaveData(ValueOutput)
* @see net.minecraft.world.entity.player.Player#addAdditionalSaveData(ValueOutput)
* @see net.minecraft.world.entity.LivingEntity#addAdditionalSaveData(ValueOutput)
@@ -47,33 +47,23 @@ public class OpenPlayer extends CraftPlayer {
"TicksFrozen",
"HasVisualFire",
"Tags",
"data",
"Passengers",
// ServerPlayer#addAdditionalSaveData(CompoundTag)
// Intentional omissions to prevent mount loss: Attach, Entity, and RootVehicle
"warden_spawn_tracker",
"entered_nether_pos", // Replaces enteredNetherPosition
"enteredNetherPosition",
"respawn", // Replaces SpawnXyz fields as of 1.21.6
"SpawnX",
"SpawnY",
"SpawnZ",
"SpawnForced",
"SpawnAngle",
"SpawnDimension",
"entered_nether_pos",
"last_explosion_impact_pos",
"respawn",
"raid_omen_position",
"ender_pearls",
// Player#addAdditionalSaveData(CompoundTag)
"ShoulderEntityLeft",
"ShoulderEntityRight",
// Player#addAdditionalSaveData(CompoundTag)
"LastDeathLocation",
"current_explosion_impact_pos",
// LivingEntity#addAdditionalSaveData(CompoundTag)
"current_explosion_impact_pos",
"active_effects",
"sleeping_pos", // Replaces SleepingXyz fields as of 1.21.6
"SleepingX",
"SleepingY",
"SleepingZ",
"Brain",
"sleeping_pos",
"last_hurt_by_player",
"last_hurt_by_player_memory_time",
"last_hurt_by_mob",
@@ -1,8 +1,8 @@
package com.github.jikoo.openinv.internal.spigot26_1.player;
package com.github.jikoo.openinv.internal.spigot26_2.player;
import com.github.jikoo.openinv.internal.spigot26_1.container.OpenEnderChest;
import com.github.jikoo.openinv.internal.spigot26_1.container.OpenInventory;
import com.github.jikoo.openinv.internal.spigot26_1.container.menu.OpenChestMenu;
import com.github.jikoo.openinv.internal.spigot26_2.container.OpenEnderChest;
import com.github.jikoo.openinv.internal.spigot26_2.container.OpenInventory;
import com.github.jikoo.openinv.internal.spigot26_2.container.menu.OpenChestMenu;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.util.JulLoggerAdapter;
import com.mojang.authlib.GameProfile;
@@ -11,6 +11,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.PlayerAdvancements;
import net.minecraft.server.level.ClientInformation;
import net.minecraft.server.level.ParticleStatus;
import net.minecraft.server.level.ServerLevel;
@@ -90,7 +91,7 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
ServerPlayer entity = createNewPlayer(server, worldServer, offline);
// Stop listening for advancement progression - if this is not cleaned up, loading causes a memory leak.
entity.getAdvancements().stopListening();
removeListeners(entity.getAdvancements());
// Try to load the player's data.
if (loadData(entity)) {
@@ -139,6 +140,10 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
return entity;
}
protected void removeListeners(@NotNull PlayerAdvancements advancements) {
advancements.clearTriggers();
}
boolean loadData(@NotNull ServerPlayer player) {
// See CraftPlayer#loadData
+7 -4
View File
@@ -11,6 +11,9 @@ dependencies {
compileOnly(libs.spigotapi)
implementation(project(":openinvapi"))
implementation(project(":openinvcommon"))
implementation(project(":openinvadapterpaper26_2")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
implementation(project(":openinvadapterpaper26_1")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
@@ -20,11 +23,11 @@ dependencies {
implementation(project(":openinvadapterpaper1_21_10")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
}
implementation(project(":openinvadapterpaper1_21_8")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
implementation(project(":openinvadapterspigot26_2")) {
exclude(group = "org.spigotmc", module = "spigot")
}
implementation(project(":openinvadapterspigot")) {
exclude(group = "io.papermc.paper", module = "dev-bundle")
implementation(project(":openinvadapterspigot26_1")) {
exclude(group = "org.spigotmc", module = "spigot")
}
implementation(libs.planarwrappers)
implementation(libs.folia.scheduler.wrapper)
@@ -188,7 +188,7 @@ public class OpenInv extends FoliaWrappedJavaPlugin implements IOpenInv {
private void sendVersionError(@NotNull Consumer<String> messageMethod) {
if (!accessor.isSupported()) {
messageMethod.accept("Your server version (" + accessor.getVersion() + ") is not supported.");
messageMethod.accept("Please download the correct version of OpenInv here: " + accessor.getReleasesLink());
messageMethod.accept("Please check https://github.com/Jikoo/OpenInv/wiki/Supported-Versions to find a matching OI version.");
}
if (!isSpigot) {
messageMethod.accept("OpenInv requires that you use Spigot or a Spigot fork. Per the 1.14 update thread");
@@ -65,6 +65,9 @@ public class InternalAccessor {
private @Nullable Accessor getAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
if (!PAPER) {
if (BukkitVersions.MINECRAFT.equals(Version.of(26, 2))) {
return new com.github.jikoo.openinv.internal.spigot26_2.InternalAccessor(logger, lang);
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(26, 1))
&& BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(26, 1, 2))) {
// Load Spigot accessor.
@@ -73,8 +76,8 @@ public class InternalAccessor {
return null;
}
Version maxSupported = Version.of(26, 1, 2);
Version minSupported = Version.of(1, 21, 6);
Version maxSupported = Version.of(26, 2);
Version minSupported = Version.of(1, 21, 9);
// Ensure version is in supported range.
if (BukkitVersions.MINECRAFT.greaterThan(maxSupported) || BukkitVersions.MINECRAFT.lessThan(minSupported)) {
@@ -82,142 +85,17 @@ public class InternalAccessor {
}
// Paper or a Paper fork, can use Mojang-mapped internals.
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(26, 2))) { // 26.2
return new com.lishid.openinv.internal.paper26_2.InternalAccessor(logger, lang);
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(26, 1))) { // 26.1.1, 26.1.2
return new com.lishid.openinv.internal.paper26_1.InternalAccessor(logger, lang);
}
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 21, 11))) {
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 21, 11))) { // 1.21.11
return new com.lishid.openinv.internal.paper1_21_11.InternalAccessor(logger, lang);
}
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 21, 10))
&& BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 9))) { // 1.21.9, 1.21.10
return new com.lishid.openinv.internal.paper1_21_10.InternalAccessor(logger, lang);
}
return new com.lishid.openinv.internal.paper1_21_8.InternalAccessor(logger, lang);
}
public String getReleasesLink() {
if (PAPER) {
// Paper 1.21.1+
return getPaperReleaseLink();
}
// Spigot 1.21.1+
return getSpigotReleaseLink();
}
private String getPaperReleaseLink() {
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 6))) {
return "https://github.com/Jikoo/OpenInv/releases";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 1))) {
return "https://github.com/Jikoo/OpenInv/releases/tag/5.3.0";
}
return getLegacyReleaseLink();
}
private String getSpigotReleaseLink() {
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(26, 1))) {
return "https://github.com/Jikoo/OpenInv/releases";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 11))) { // 1.21.11
return "https://github.com/Jikoo/OpenInv/releases/tag/5.3.0";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 10))) { // 1.21.10
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.15";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 9))) { // 1.21.9
return "Unsupported; upgrade to 1.21.10: https://github.com/Jikoo/OpenInv/releases/tag/5.1.15";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 8))) { // 1.21.8, 1.21.7
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.13";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 6))) { // 1.21.6
return "Unsupported; upgrade to 1.21.7: https://github.com/Jikoo/OpenInv/releases/tag/5.1.13";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 5))) { // 1.21.5
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.11";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 4))) { // 1.21.4
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.9";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 3))) { // 1.21.3
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.6";
}
if (BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 1))) { // 1.21.1, 1.21.2
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.3";
}
// 1.21.0 and lower
return getLegacyReleaseLink();
}
private String getLegacyReleaseLink() {
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 4, 4))) { // Good luck.
return "https://dev.bukkit.org/projects/openinv/files?&sort=datecreated";
}
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 8, 8))) { // 1.8.8
return "https://github.com/lishid/OpenInv/releases/tag/4.1.5";
}
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 13))) { // 1.4.4+ had versioned packages.
return "https://github.com/lishid/OpenInv/releases/tag/4.0.0 (OpenInv-legacy)";
}
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 13))) { // 1.13
return "https://github.com/lishid/OpenInv/releases/tag/4.0.0";
}
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 14))) { // 1.13.1, 1.13.2
return "https://github.com/lishid/OpenInv/releases/tag/4.0.7";
}
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 14))) { // 1.14 to 1.14.1 had no revision bump.
return "https://github.com/lishid/OpenInv/releases/tag/4.0.0";
}
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 14, 1))) { // 1.14.1 to 1.14.2 had no revision bump.
return "https://github.com/lishid/OpenInv/releases/tag/4.0.1";
}
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 15))) { // 1.14.2
return "https://github.com/lishid/OpenInv/releases/tag/4.1.1";
}
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 15, 1))) { // 1.15, 1.15.1
return "https://github.com/lishid/OpenInv/releases/tag/4.1.5";
}
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 16))) { // 1.15.2
return "https://github.com/Jikoo/OpenInv/commit/502f661be39ee85d300851dd571f3da226f12345 (never released)";
}
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 16, 1))) { // 1.16, 1.16.1
return "https://github.com/lishid/OpenInv/releases/tag/4.1.4";
}
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 16, 3))) { // 1.16.2, 1.16.3
return "https://github.com/lishid/OpenInv/releases/tag/4.1.5";
}
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 17))) { // 1.16.4, 1.16.5
return "https://github.com/Jikoo/OpenInv/releases/tag/4.1.8";
}
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 18, 1))) { // 1.17, 1.18, 1.18.1
return "https://github.com/Jikoo/OpenInv/releases/tag/4.1.10";
}
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 19))) { // 1.18.2
return "https://github.com/Jikoo/OpenInv/releases/tag/4.3.0";
}
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 19))) { // 1.19
return "https://github.com/Jikoo/OpenInv/releases/tag/4.2.0";
}
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 19, 1))) { // 1.19.1
return "https://github.com/Jikoo/OpenInv/releases/tag/4.2.2";
}
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 19, 3))) { // 1.19.2, 1.19.3
return "https://github.com/Jikoo/OpenInv/releases/tag/4.3.0";
}
if (BukkitVersions.MINECRAFT.lessThan(Version.of(1, 20))) { // 1.19.4
return "https://github.com/Jikoo/OpenInv/releases/tag/4.4.3";
}
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 20, 1))) { // 1.20, 1.20.1
return "https://github.com/Jikoo/OpenInv/releases/tag/4.4.1";
}
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 20, 3))) { // 1.20.2, 1.20.3
return "https://github.com/Jikoo/OpenInv/releases/tag/4.4.3";
}
if (BukkitVersions.MINECRAFT.equals(Version.of(1, 20, 5))) { // 1.20.5
return "Unsupported; upgrade to 1.20.6: https://github.com/Jikoo/OpenInv/releases/tag/5.1.2";
}
// 1.20.4, 1.20.6, 1.21
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.2";
// 1.21.9, 1.21.10
return new com.lishid.openinv.internal.paper1_21_10.InternalAccessor(logger, lang);
}
/**
@@ -2,16 +2,16 @@
"pack": {
"description": "Improve OpenInv's legibility",
"min_format": 34,
"max_format": [85, 0],
"max_format": [88, 0],
"pack_format": 64,
"supported_formats": [ 34, 85 ]
"supported_formats": [ 34, 88 ]
},
"overlays": {
"entries": [
{
"min_format": 44,
"max_format": [85, 0],
"formats": [ 44, 85 ],
"max_format": [88, 0],
"formats": [ 44, 88 ],
"directory": "openinv_44"
},
{
+3 -2
View File
@@ -18,11 +18,12 @@ if (!java.lang.Boolean.getBoolean("jitpack")) {
project(":openinvcommon").projectDir = file("common")
val internals = listOf(
"paper26_2",
"paper26_1",
"paper1_21_11",
"paper1_21_10",
"paper1_21_8",
"spigot"
"spigot26_2",
"spigot26_1"
)
for (internal in internals) {
include(":openinvadapter$internal")