mirror of
https://github.com/Jikoo/OpenInv.git
synced 2026-11-04 08:42:05 -05:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4441cdcf04 | ||
|
|
9940b9d840 | ||
|
|
fb409f8024 | ||
|
|
08b43a8aca | ||
|
|
3df3d41a7f | ||
|
|
16cba8a137 | ||
|
|
f1b86b4eb1 | ||
|
|
172e1cd55b | ||
|
|
d8b5aa145b | ||
|
|
2ffff99acf | ||
|
|
743c46f322 | ||
|
|
e3285a6d61 | ||
|
|
806fb848a7 | ||
|
|
b269a5ed3c | ||
|
|
8c102c4400 |
No files matched your search
@@ -15,7 +15,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: actions/setup-java@v5
|
||||
with:
|
||||
@@ -41,7 +41,7 @@ jobs:
|
||||
# Upload artifacts
|
||||
- name: Upload Distributable Jar
|
||||
id: upload-final
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: dist
|
||||
path: ./dist/*
|
||||
@@ -13,21 +13,21 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Download build
|
||||
uses: actions/download-artifact@v5
|
||||
uses: actions/download-artifact@v6
|
||||
with:
|
||||
name: dist
|
||||
path: dist
|
||||
|
||||
- name: Create Release
|
||||
id: create-release
|
||||
uses: softprops/action-gh-release@v2.3.3
|
||||
uses: softprops/action-gh-release@v2.5.0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
name: OpenInv ${{ env.VERSIONED_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, 1.21.8, 1.21.7, 1.21.6, 1.21.5, 1.21.4, 1.21.3, 1.21.1
|
||||
**Spigot:** TODO VERSION
|
||||
|
||||
TODO HELLO HUMAN, PRESS THE GENERATE CHANGELOG BUTTON PLEASE.
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
run: |
|
||||
mkdir -p ./pr
|
||||
echo ${{ github.event.number }} > ./pr/pr_number
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: pr_number
|
||||
path: pr/
|
||||
@@ -13,11 +13,11 @@ jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Build resource pack
|
||||
id: upload-resource-pack
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
with:
|
||||
name: openinv-legibility-pack
|
||||
path: ./resource-pack/openinv-legibility-pack/
|
||||
|
||||
@@ -138,14 +138,21 @@ public interface IOpenInv {
|
||||
boolean online
|
||||
) throws InstantiationException;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #openInventory(Player, ISpecialInventory, boolean)}
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "5.2.0")
|
||||
@Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
|
||||
|
||||
/**
|
||||
* Open an {@link ISpecialInventory} for a {@link Player}.
|
||||
*
|
||||
* @param player the viewer
|
||||
* @param inventory the inventory to open
|
||||
* @param viewOnly whether the inventory should be view-only
|
||||
* @return the resulting {@link InventoryView}
|
||||
*/
|
||||
@Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
|
||||
@Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory, boolean viewOnly);
|
||||
|
||||
/**
|
||||
* Check if a {@link Player} is currently loaded by OpenInv.
|
||||
|
||||
@@ -42,6 +42,9 @@ public enum Permissions {
|
||||
ACCESS_CROSSWORLD("access.crossworld"),
|
||||
ACCESS_OFFLINE("access.offline"),
|
||||
ACCESS_ONLINE("access.online"),
|
||||
ACCESS_EQUAL_EDIT("access.equal.edit"),
|
||||
ACCESS_EQUAL_VIEW("access.equal.view"),
|
||||
ACCESS_EQUAL_DENY("access.equal.deny"),
|
||||
|
||||
SPECTATE_CLICK("spectate.click"),
|
||||
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
# Project meta
|
||||
group=com.lishid.openinv
|
||||
version=5.1.14
|
||||
version=5.2.0
|
||||
description=A Bukkit plugin for opening normally-inaccessible inventories.
|
||||
|
||||
# Gradle configuration
|
||||
|
||||
@@ -6,7 +6,7 @@ annotations = "26.0.2-1"
|
||||
paperweight = "2.0.0-beta.17"
|
||||
shadow = "9.2.2"
|
||||
folia-scheduler-wrapper = "v0.0.3"
|
||||
errorprone-core = "2.42.0"
|
||||
errorprone-core = "2.45.0"
|
||||
errorprone-gradle = "4.2.0"
|
||||
slf4j = "2.0.17"
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ dependencies {
|
||||
implementation(project(":openinvapi"))
|
||||
implementation(project(":openinvcommon"))
|
||||
|
||||
paperweight.paperDevBundle("1.21.10-R0.1-SNAPSHOT")
|
||||
paperweight.paperDevBundle("1.21.11-R0.1-SNAPSHOT")
|
||||
}
|
||||
|
||||
val spigot = tasks.register<ShadowJar>("spigotRelocations") {
|
||||
|
||||
+3
-3
@@ -3,6 +3,7 @@ package com.lishid.openinv.internal.common.container;
|
||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||
import com.lishid.openinv.internal.InternalOwned;
|
||||
import com.lishid.openinv.internal.common.container.bukkit.OpenPlayerInventory;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenInventoryMenu;
|
||||
import com.lishid.openinv.internal.common.container.slot.Content;
|
||||
import com.lishid.openinv.internal.common.container.slot.ContentCrafting;
|
||||
@@ -24,7 +25,6 @@ import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.bukkit.Location;
|
||||
@@ -199,7 +199,7 @@ public abstract class BaseOpenInventory implements Container, InternalOwned<Serv
|
||||
return slots.get(index).getSlotType();
|
||||
}
|
||||
|
||||
public abstract Component getTitle(ServerPlayer player);
|
||||
public abstract Component getTitle(ServerPlayer player, @Nullable OpenChestMenu<?> menu);
|
||||
|
||||
@Override
|
||||
public ServerPlayer getOwnerHandle() {
|
||||
@@ -325,7 +325,7 @@ public abstract class BaseOpenInventory implements Container, InternalOwned<Serv
|
||||
owner.containerMenu.setCarried(ItemStack.EMPTY);
|
||||
}
|
||||
|
||||
public @Nullable AbstractContainerMenu createMenu(Player player, int i, boolean viewOnly) {
|
||||
public @Nullable OpenChestMenu<?> createMenu(Player player, int i, boolean viewOnly) {
|
||||
if (player instanceof ServerPlayer serverPlayer) {
|
||||
return new OpenInventoryMenu(this, serverPlayer, i, viewOnly);
|
||||
}
|
||||
|
||||
+12
-4
@@ -2,16 +2,17 @@ package com.lishid.openinv.internal.common.container;
|
||||
|
||||
import com.lishid.openinv.internal.ISpecialEnderChest;
|
||||
import com.lishid.openinv.internal.InternalOwned;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenEnderChestMenu;
|
||||
import com.lishid.openinv.internal.common.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.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.StackedContentsCompatible;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.bukkit.Location;
|
||||
@@ -177,13 +178,20 @@ public class OpenEnderChest implements Container, StackedContentsCompatible, Int
|
||||
}
|
||||
}
|
||||
|
||||
public Component getTitle() {
|
||||
return Component.translatableWithFallback("openinv.container.enderchest.prefix", "", owner.getName())
|
||||
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 AbstractContainerMenu createMenu(Player player, int i, boolean viewOnly) {
|
||||
public @Nullable OpenChestMenu<?> createMenu(Player player, int i, boolean viewOnly) {
|
||||
if (player instanceof ServerPlayer serverPlayer) {
|
||||
return new OpenEnderChestMenu(this, serverPlayer, i, viewOnly);
|
||||
}
|
||||
|
||||
+10
-4
@@ -1,10 +1,11 @@
|
||||
package com.lishid.openinv.internal.common.container;
|
||||
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.FontDescription;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -17,22 +18,27 @@ public class OpenInventory extends BaseOpenInventory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component getTitle(@Nullable ServerPlayer viewer) {
|
||||
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(new FontDescription.Resource(ResourceLocation.parse("openinv:font/inventory")))
|
||||
.withFont(new FontDescription.Resource(Identifier.parse("openinv:font/inventory")))
|
||||
.withColor(ChatFormatting.WHITE)));
|
||||
} else {
|
||||
component.append(
|
||||
Component.translatableWithFallback("openinv.container.inventory.other", "")
|
||||
.withStyle(style -> style
|
||||
.withFont(new FontDescription.Resource(ResourceLocation.parse("openinv:font/inventory")))
|
||||
.withFont(new FontDescription.Resource(Identifier.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"))
|
||||
|
||||
+5
-221
@@ -1,26 +1,16 @@
|
||||
package com.lishid.openinv.internal.common.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.common.container.bukkit.OpenDummyInventory;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotPlaceholder;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.network.HashedStack;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.ChestMenu;
|
||||
import net.minecraft.world.inventory.ClickType;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
import net.minecraft.world.inventory.ContainerListener;
|
||||
import net.minecraft.world.inventory.ContainerSynchronizer;
|
||||
import net.minecraft.world.inventory.DataSlot;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.inventory.RemoteSlot;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
|
||||
@@ -30,14 +20,9 @@ import org.bukkit.inventory.InventoryView;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An extension of {@link AbstractContainerMenu} that supports {@link SlotPlaceholder placeholders}.
|
||||
* An extension of {@link AbstractContainerMenu} storing and managing data common to all special inventories.
|
||||
*/
|
||||
@SuppressWarnings("HidingField") // Revisit when removing 1.21.4 support
|
||||
public abstract class OpenChestMenu<T extends Container & ISpecialInventory & InternalOwned<ServerPlayer>>
|
||||
extends AbstractContainerMenu {
|
||||
|
||||
@@ -49,13 +34,6 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
protected final boolean ownContainer;
|
||||
protected final int topSize;
|
||||
private CraftInventoryView<OpenChestMenu<T>, Inventory> bukkitEntity;
|
||||
// Syncher fields
|
||||
protected @Nullable ContainerSynchronizer synchronizer;
|
||||
protected final List<DataSlot> dataSlots = new ArrayList<>();
|
||||
protected final IntList remoteDataSlots = new IntArrayList();
|
||||
protected final List<ContainerListener> containerListeners = new ArrayList<>();
|
||||
private RemoteSlot remoteCarried = RemoteSlot.PLACEHOLDER;
|
||||
protected boolean suppressRemoteUpdates;
|
||||
|
||||
protected OpenChestMenu(
|
||||
@NotNull MenuType<ChestMenu> type,
|
||||
@@ -125,6 +103,7 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
protected void preSlotSetup() {
|
||||
}
|
||||
|
||||
@@ -136,6 +115,9 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
return slot;
|
||||
}
|
||||
|
||||
public boolean isViewOnly() {
|
||||
return viewOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final @NotNull CraftInventoryView<OpenChestMenu<T>, Inventory> getBukkitView() {
|
||||
@@ -303,202 +285,4 @@ public abstract class OpenChestMenu<T extends Container & ISpecialInventory & In
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overrides from here on are purely to modify the sync process to send placeholder items.
|
||||
@Override
|
||||
protected @NotNull Slot addSlot(@NotNull Slot slot) {
|
||||
slot.index = this.slots.size();
|
||||
this.slots.add(slot);
|
||||
this.lastSlots.add(ItemStack.EMPTY);
|
||||
this.remoteSlots.add(this.synchronizer != null ? this.synchronizer.createSlot() : RemoteSlot.PLACEHOLDER);
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull DataSlot addDataSlot(@NotNull DataSlot dataSlot) {
|
||||
this.dataSlots.add(dataSlot);
|
||||
this.remoteDataSlots.add(0);
|
||||
return dataSlot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDataSlots(ContainerData containerData) {
|
||||
for (int i = 0; i < containerData.getCount(); i++) {
|
||||
this.addDataSlot(DataSlot.forContainer(containerData, i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSlotListener(@NotNull ContainerListener containerListener) {
|
||||
if (!this.containerListeners.contains(containerListener)) {
|
||||
this.containerListeners.add(containerListener);
|
||||
this.broadcastChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSynchronizer(@NotNull ContainerSynchronizer containerSynchronizer) {
|
||||
this.synchronizer = containerSynchronizer;
|
||||
this.remoteCarried = synchronizer.createSlot();
|
||||
this.remoteSlots.replaceAll(slot -> synchronizer.createSlot());
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAllDataToRemote() {
|
||||
List<ItemStack> contentsCopy = new ArrayList<>();
|
||||
for (int index = 0; index < slots.size(); ++index) {
|
||||
Slot slot = slots.get(index);
|
||||
ItemStack itemStack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
|
||||
contentsCopy.add(itemStack);
|
||||
this.remoteSlots.get(index).force(itemStack);
|
||||
}
|
||||
|
||||
remoteCarried.force(getCarried());
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
this.remoteDataSlots.set(index, this.dataSlots.get(index).get());
|
||||
}
|
||||
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendInitialData(this, contentsCopy, this.getCarried().copy(), this.remoteDataSlots.toIntArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceSlot(@NotNull Container container, int slot) {
|
||||
int slotsIndex = this.findSlot(container, slot).orElse(-1);
|
||||
if (slotsIndex != -1) {
|
||||
ItemStack item = this.slots.get(slotsIndex).getItem();
|
||||
this.remoteSlots.get(slotsIndex).force(item);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendSlotChange(this, slotsIndex, item.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastCarriedItem() {
|
||||
ItemStack carried = this.getCarried();
|
||||
this.remoteCarried.force(carried);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, carried.copy());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSlotListener(@NotNull ContainerListener containerListener) {
|
||||
this.containerListeners.remove(containerListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastChanges() {
|
||||
for (int index = 0; index < this.slots.size(); ++index) {
|
||||
Slot slot = this.slots.get(index);
|
||||
ItemStack itemstack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
|
||||
Supplier<ItemStack> supplier = Suppliers.memoize(itemstack::copy);
|
||||
this.triggerSlotListeners(index, itemstack, supplier);
|
||||
this.synchronizeSlotToRemote(index, itemstack, supplier);
|
||||
}
|
||||
|
||||
this.synchronizeCarriedToRemote();
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
DataSlot dataSlot = this.dataSlots.get(index);
|
||||
int j = dataSlot.get();
|
||||
if (dataSlot.checkAndClearUpdateFlag()) {
|
||||
this.updateDataSlotListeners(index, j);
|
||||
}
|
||||
|
||||
this.synchronizeDataSlotToRemote(index, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastFullState() {
|
||||
for (int index = 0; index < this.slots.size(); ++index) {
|
||||
ItemStack itemstack = this.slots.get(index).getItem();
|
||||
this.triggerSlotListeners(index, itemstack, itemstack::copy);
|
||||
}
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
DataSlot containerproperty = this.dataSlots.get(index);
|
||||
if (containerproperty.checkAndClearUpdateFlag()) {
|
||||
this.updateDataSlotListeners(index, containerproperty.get());
|
||||
}
|
||||
}
|
||||
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
private void updateDataSlotListeners(int i, int j) {
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.dataChanged(this, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerSlotListeners(int index, @NotNull ItemStack itemStack, @NotNull Supplier<ItemStack> supplier) {
|
||||
ItemStack itemStack1 = this.lastSlots.get(index);
|
||||
if (!ItemStack.matches(itemStack1, itemStack)) {
|
||||
ItemStack itemStack2 = supplier.get();
|
||||
this.lastSlots.set(index, itemStack2);
|
||||
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.slotChanged(this, index, itemStack2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void synchronizeSlotToRemote(int i, @NotNull ItemStack itemStack, @NotNull Supplier<ItemStack> supplier) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
RemoteSlot slot = this.remoteSlots.get(i);
|
||||
if (!slot.matches(itemStack)) {
|
||||
slot.force(itemStack);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendSlotChange(this, i, supplier.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeDataSlotToRemote(int index, int value) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
int existing = this.remoteDataSlots.getInt(index);
|
||||
if (existing != value) {
|
||||
this.remoteDataSlots.set(index, value);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendDataChange(this, index, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeCarriedToRemote() {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
ItemStack carried = this.getCarried();
|
||||
if (!this.remoteCarried.matches(carried)) {
|
||||
this.remoteCarried.force(carried);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, carried.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoteCarried(@NotNull HashedStack stack) {
|
||||
this.remoteCarried.receive(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suppressRemoteUpdates() {
|
||||
this.suppressRemoteUpdates = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resumeRemoteUpdates() {
|
||||
this.suppressRemoteUpdates = false;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -7,7 +7,7 @@ import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OpenEnderChestMenu extends OpenChestMenu<OpenEnderChest> {
|
||||
public class OpenEnderChestMenu extends OpenSyncMenu<OpenEnderChest> {
|
||||
|
||||
public OpenEnderChestMenu(
|
||||
@NotNull OpenEnderChest enderChest,
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ import org.bukkit.inventory.InventoryView;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class OpenInventoryMenu extends OpenChestMenu<BaseOpenInventory> {
|
||||
public class OpenInventoryMenu extends OpenSyncMenu<BaseOpenInventory> {
|
||||
|
||||
private int offset;
|
||||
|
||||
|
||||
+251
@@ -0,0 +1,251 @@
|
||||
package com.lishid.openinv.internal.common.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.common.container.slot.SlotPlaceholder;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.network.HashedStack;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.inventory.ChestMenu;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
import net.minecraft.world.inventory.ContainerListener;
|
||||
import net.minecraft.world.inventory.ContainerSynchronizer;
|
||||
import net.minecraft.world.inventory.DataSlot;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.inventory.RemoteSlot;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An extension of {@link OpenChestMenu} that supports {@link SlotPlaceholder placeholders}.
|
||||
*/
|
||||
@SuppressWarnings("HidingField") // Revisit when removing 1.21.4 support
|
||||
public abstract class OpenSyncMenu<T extends Container & ISpecialInventory & InternalOwned<ServerPlayer>>
|
||||
extends OpenChestMenu<T> {
|
||||
|
||||
// Syncher fields
|
||||
protected @Nullable ContainerSynchronizer synchronizer;
|
||||
protected final List<DataSlot> dataSlots = new ArrayList<>();
|
||||
protected final IntList remoteDataSlots = new IntArrayList();
|
||||
protected final List<ContainerListener> containerListeners = new ArrayList<>();
|
||||
private RemoteSlot remoteCarried = RemoteSlot.PLACEHOLDER;
|
||||
protected boolean suppressRemoteUpdates;
|
||||
|
||||
protected OpenSyncMenu(
|
||||
@NotNull MenuType<ChestMenu> type,
|
||||
int containerCounter,
|
||||
@NotNull T container,
|
||||
@NotNull ServerPlayer viewer,
|
||||
boolean viewOnly
|
||||
) {
|
||||
super(type, containerCounter, container, viewer, viewOnly);
|
||||
}
|
||||
|
||||
// Overrides from here on are purely to modify the sync process to send placeholder items.
|
||||
@Override
|
||||
protected @NotNull Slot addSlot(@NotNull Slot slot) {
|
||||
slot.index = this.slots.size();
|
||||
this.slots.add(slot);
|
||||
this.lastSlots.add(ItemStack.EMPTY);
|
||||
this.remoteSlots.add(this.synchronizer != null ? this.synchronizer.createSlot() : RemoteSlot.PLACEHOLDER);
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull DataSlot addDataSlot(@NotNull DataSlot dataSlot) {
|
||||
this.dataSlots.add(dataSlot);
|
||||
this.remoteDataSlots.add(0);
|
||||
return dataSlot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDataSlots(ContainerData containerData) {
|
||||
for (int i = 0; i < containerData.getCount(); i++) {
|
||||
this.addDataSlot(DataSlot.forContainer(containerData, i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSlotListener(@NotNull ContainerListener containerListener) {
|
||||
if (!this.containerListeners.contains(containerListener)) {
|
||||
this.containerListeners.add(containerListener);
|
||||
this.broadcastChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSynchronizer(@NotNull ContainerSynchronizer containerSynchronizer) {
|
||||
this.synchronizer = containerSynchronizer;
|
||||
this.remoteCarried = synchronizer.createSlot();
|
||||
this.remoteSlots.replaceAll(slot -> synchronizer.createSlot());
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAllDataToRemote() {
|
||||
List<ItemStack> contentsCopy = new ArrayList<>();
|
||||
for (int index = 0; index < slots.size(); ++index) {
|
||||
Slot slot = slots.get(index);
|
||||
ItemStack itemStack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
|
||||
contentsCopy.add(itemStack);
|
||||
this.remoteSlots.get(index).force(itemStack);
|
||||
}
|
||||
|
||||
remoteCarried.force(getCarried());
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
this.remoteDataSlots.set(index, this.dataSlots.get(index).get());
|
||||
}
|
||||
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendInitialData(this, contentsCopy, this.getCarried().copy(), this.remoteDataSlots.toIntArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forceSlot(@NotNull Container container, int slot) {
|
||||
int slotsIndex = this.findSlot(container, slot).orElse(-1);
|
||||
if (slotsIndex != -1) {
|
||||
ItemStack item = this.slots.get(slotsIndex).getItem();
|
||||
this.remoteSlots.get(slotsIndex).force(item);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendSlotChange(this, slotsIndex, item.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastCarriedItem() {
|
||||
ItemStack carried = this.getCarried();
|
||||
this.remoteCarried.force(carried);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, carried.copy());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSlotListener(@NotNull ContainerListener containerListener) {
|
||||
this.containerListeners.remove(containerListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastChanges() {
|
||||
for (int index = 0; index < this.slots.size(); ++index) {
|
||||
Slot slot = this.slots.get(index);
|
||||
ItemStack itemstack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
|
||||
Supplier<ItemStack> supplier = Suppliers.memoize(itemstack::copy);
|
||||
this.triggerSlotListeners(index, itemstack, supplier);
|
||||
this.synchronizeSlotToRemote(index, itemstack, supplier);
|
||||
}
|
||||
|
||||
this.synchronizeCarriedToRemote();
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
DataSlot dataSlot = this.dataSlots.get(index);
|
||||
int j = dataSlot.get();
|
||||
if (dataSlot.checkAndClearUpdateFlag()) {
|
||||
this.updateDataSlotListeners(index, j);
|
||||
}
|
||||
|
||||
this.synchronizeDataSlotToRemote(index, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastFullState() {
|
||||
for (int index = 0; index < this.slots.size(); ++index) {
|
||||
ItemStack itemstack = this.slots.get(index).getItem();
|
||||
this.triggerSlotListeners(index, itemstack, itemstack::copy);
|
||||
}
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
DataSlot containerproperty = this.dataSlots.get(index);
|
||||
if (containerproperty.checkAndClearUpdateFlag()) {
|
||||
this.updateDataSlotListeners(index, containerproperty.get());
|
||||
}
|
||||
}
|
||||
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
private void updateDataSlotListeners(int i, int j) {
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.dataChanged(this, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void triggerSlotListeners(int index, @NotNull ItemStack itemStack, @NotNull Supplier<ItemStack> supplier) {
|
||||
ItemStack itemStack1 = this.lastSlots.get(index);
|
||||
if (!ItemStack.matches(itemStack1, itemStack)) {
|
||||
ItemStack itemStack2 = supplier.get();
|
||||
this.lastSlots.set(index, itemStack2);
|
||||
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.slotChanged(this, index, itemStack2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void synchronizeSlotToRemote(int i, @NotNull ItemStack itemStack, @NotNull Supplier<ItemStack> supplier) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
RemoteSlot slot = this.remoteSlots.get(i);
|
||||
if (!slot.matches(itemStack)) {
|
||||
slot.force(itemStack);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendSlotChange(this, i, supplier.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeDataSlotToRemote(int index, int value) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
int existing = this.remoteDataSlots.getInt(index);
|
||||
if (existing != value) {
|
||||
this.remoteDataSlots.set(index, value);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendDataChange(this, index, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeCarriedToRemote() {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
ItemStack carried = this.getCarried();
|
||||
if (!this.remoteCarried.matches(carried)) {
|
||||
this.remoteCarried.force(carried);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, carried.copy());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoteCarried(@NotNull HashedStack stack) {
|
||||
this.remoteCarried.receive(stack);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suppressRemoteUpdates() {
|
||||
this.suppressRemoteUpdates = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resumeRemoteUpdates() {
|
||||
this.suppressRemoteUpdates = false;
|
||||
}
|
||||
|
||||
}
|
||||
+51
-6
@@ -1,10 +1,13 @@
|
||||
package com.lishid.openinv.internal.common.player;
|
||||
|
||||
import com.lishid.openinv.event.OpenEvents;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.nbt.NumericTag;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||
import net.minecraft.world.level.storage.ValueOutput;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.bukkit.craftbukkit.entity.CraftPlayer;
|
||||
@@ -13,6 +16,9 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.annotations.Unmodifiable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Set;
|
||||
|
||||
public abstract class BaseOpenPlayer extends CraftPlayer {
|
||||
@@ -21,7 +27,7 @@ public abstract class BaseOpenPlayer extends CraftPlayer {
|
||||
* List of tags to always reset when saving. These are items that do not get written
|
||||
* if unset or empty, resulting in older values not being clobbered appropriately.
|
||||
*
|
||||
* @see net.minecraft.world.entity.Entity#saveWithoutId(ValueOutput)
|
||||
* @see net.minecraft.world.entity.Entity#saveWithoutId(ValueOutput, boolean, boolean, boolean)
|
||||
* @see net.minecraft.server.level.ServerPlayer#addAdditionalSaveData(ValueOutput)
|
||||
* @see net.minecraft.world.entity.player.Player#addAdditionalSaveData(ValueOutput)
|
||||
* @see net.minecraft.world.entity.LivingEntity#addAdditionalSaveData(ValueOutput)
|
||||
@@ -41,8 +47,8 @@ public abstract class BaseOpenPlayer extends CraftPlayer {
|
||||
"Passengers",
|
||||
// ServerPlayer#addAdditionalSaveData(CompoundTag)
|
||||
// Intentional omissions to prevent mount loss: Attach, Entity, and RootVehicle
|
||||
"warden_spawn_tracker",
|
||||
"entered_nether_pos", // Replaces enteredNetherPosition
|
||||
"warden_spawn_tracker", // No longer needed as of 1.21.11
|
||||
"entered_nether_pos", // Replaces enteredNetherPosition as of 1.21.6
|
||||
"enteredNetherPosition",
|
||||
"respawn", // Replaces SpawnXyz fields as of 1.21.6
|
||||
"SpawnX",
|
||||
@@ -86,7 +92,40 @@ public abstract class BaseOpenPlayer extends CraftPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract void saveData();
|
||||
public void saveData() {
|
||||
if (OpenEvents.saveCancelled(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
trySave(this.getHandle());
|
||||
}
|
||||
|
||||
protected abstract void trySave(ServerPlayer player);
|
||||
|
||||
protected void saveSafe(
|
||||
@NotNull ServerPlayer player,
|
||||
@Nullable CompoundTag oldData,
|
||||
@NotNull CompoundTag playerData,
|
||||
@NotNull PlayerDataStorage worldNbtStorage
|
||||
) throws IOException {
|
||||
// Revert certain special data values when offline.
|
||||
revertSpecialValues(playerData, oldData);
|
||||
|
||||
Path playerDataDir = worldNbtStorage.getPlayerDir().toPath();
|
||||
Path tempFile = Files.createTempFile(playerDataDir, player.getStringUUID() + "-", ".dat");
|
||||
NbtIo.writeCompressed(playerData, tempFile);
|
||||
Path dataFile = playerDataDir.resolve(player.getStringUUID() + ".dat");
|
||||
Path backupFile = playerDataDir.resolve(player.getStringUUID() + ".dat_old");
|
||||
safeReplaceFile(dataFile, tempFile, backupFile);
|
||||
}
|
||||
|
||||
protected void safeReplaceFile(
|
||||
@NotNull Path dataFile,
|
||||
@NotNull Path tempFile,
|
||||
@NotNull Path backupFile
|
||||
) {
|
||||
net.minecraft.util.Util.safeReplaceFile(dataFile, tempFile, backupFile);
|
||||
}
|
||||
|
||||
@Contract("null -> new")
|
||||
protected @NotNull CompoundTag getWritableTag(@Nullable CompoundTag oldData) {
|
||||
@@ -107,7 +146,11 @@ public abstract class BaseOpenPlayer extends CraftPlayer {
|
||||
return oldData;
|
||||
}
|
||||
|
||||
protected void revertSpecialValues(@NotNull CompoundTag newData, @NotNull CompoundTag oldData) {
|
||||
protected void revertSpecialValues(@NotNull CompoundTag newData, @Nullable CompoundTag oldData) {
|
||||
if (oldData == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Revert automatic updates to play timestamps.
|
||||
copyValue(oldData, newData, "bukkit", "lastPlayed", NumericTag.class);
|
||||
copyValue(oldData, newData, "Paper", "LastSeen", NumericTag.class);
|
||||
@@ -154,12 +197,14 @@ public abstract class BaseOpenPlayer extends CraftPlayer {
|
||||
@Nullable T data
|
||||
) {
|
||||
if (data == null) {
|
||||
container.remove(key);
|
||||
remove(container, key);
|
||||
} else {
|
||||
container.put(key, data);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void remove(@NotNull CompoundTag tag, @NotNull String key);
|
||||
|
||||
public static boolean isConnected(@Nullable ServerGamePacketListenerImpl connection) {
|
||||
return connection != null && !connection.isDisconnected();
|
||||
}
|
||||
|
||||
+10
-25
@@ -1,21 +1,16 @@
|
||||
package com.lishid.openinv.internal.common.player;
|
||||
|
||||
import com.lishid.openinv.event.OpenEvents;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.ProblemReporter;
|
||||
import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||
import net.minecraft.world.level.storage.TagValueOutput;
|
||||
import net.minecraft.world.level.storage.ValueOutput;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class OpenPlayer extends BaseOpenPlayer {
|
||||
|
||||
protected OpenPlayer(
|
||||
@@ -27,39 +22,29 @@ public class OpenPlayer extends BaseOpenPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveData() {
|
||||
if (OpenEvents.saveCancelled(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPlayer player = this.getHandle();
|
||||
protected void trySave(ServerPlayer player) {
|
||||
Logger logger = LogUtils.getLogger();
|
||||
// See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman)
|
||||
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), logger)) {
|
||||
PlayerDataStorage worldNBTStorage = server.getServer().getPlayerList().playerIo;
|
||||
PlayerDataStorage worldNbtStorage = server.getServer().getPlayerList().playerIo;
|
||||
|
||||
CompoundTag oldData = isOnline()
|
||||
? null
|
||||
: worldNBTStorage.load(player.nameAndId()).orElse(null);
|
||||
: worldNbtStorage.load(player.nameAndId()).orElse(null);
|
||||
CompoundTag playerData = getWritableTag(oldData);
|
||||
|
||||
ValueOutput valueOutput = TagValueOutput.createWrappingWithContext(scopedCollector, player.registryAccess(), playerData);
|
||||
player.saveWithoutId(valueOutput);
|
||||
|
||||
if (oldData != null) {
|
||||
// Revert certain special data values when offline.
|
||||
revertSpecialValues(playerData, oldData);
|
||||
}
|
||||
|
||||
Path playerDataDir = worldNBTStorage.getPlayerDir().toPath();
|
||||
Path tempFile = Files.createTempFile(playerDataDir, player.getStringUUID() + "-", ".dat");
|
||||
NbtIo.writeCompressed(playerData, tempFile);
|
||||
Path dataFile = playerDataDir.resolve(player.getStringUUID() + ".dat");
|
||||
Path backupFile = playerDataDir.resolve(player.getStringUUID() + ".dat_old");
|
||||
Util.safeReplaceFile(dataFile, tempFile, backupFile);
|
||||
saveSafe(player, oldData, playerData, worldNbtStorage);
|
||||
} catch (Exception e) {
|
||||
LogUtils.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void remove(@NotNull CompoundTag tag, @NotNull String key) {
|
||||
tag.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
+10
-10
@@ -3,7 +3,7 @@ package com.lishid.openinv.internal.common.player;
|
||||
import com.lishid.openinv.internal.ISpecialInventory;
|
||||
import com.lishid.openinv.internal.common.container.BaseOpenInventory;
|
||||
import com.lishid.openinv.internal.common.container.OpenEnderChest;
|
||||
import com.lishid.openinv.internal.common.container.OpenInventory;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import com.lishid.openinv.util.JulLoggerAdapter;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import io.papermc.paper.adventure.PaperAdventure;
|
||||
@@ -242,14 +242,14 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
|
||||
}
|
||||
|
||||
// See net.minecraft.server.level.ServerPlayer#openMenu(MenuProvider)
|
||||
AbstractContainerMenu menu;
|
||||
OpenChestMenu<?> menu;
|
||||
Component title;
|
||||
if (inventory instanceof BaseOpenInventory playerInv) {
|
||||
menu = playerInv.createMenu(player, player.nextContainerCounter(), viewOnly);
|
||||
title = playerInv.getTitle(player);
|
||||
title = playerInv.getTitle(player, menu);
|
||||
} else if (inventory instanceof OpenEnderChest enderChest) {
|
||||
menu = enderChest.createMenu(player, player.nextContainerCounter(), viewOnly);
|
||||
title = enderChest.getTitle();
|
||||
title = enderChest.getTitle(menu);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -265,10 +265,10 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
|
||||
menu.setTitle(title);
|
||||
|
||||
var pair = CraftEventFactory.callInventoryOpenEventWithTitle(player, menu);
|
||||
menu = pair.getSecond();
|
||||
AbstractContainerMenu opened = pair.getSecond();
|
||||
|
||||
// Menu is null if event is cancelled.
|
||||
if (menu == null) {
|
||||
if (opened == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -277,11 +277,11 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
|
||||
title = PaperAdventure.asVanilla(newTitle);
|
||||
}
|
||||
|
||||
player.containerMenu = menu;
|
||||
player.connection.send(new ClientboundOpenScreenPacket(menu.containerId, menu.getType(), title));
|
||||
player.initMenu(menu);
|
||||
player.containerMenu = opened;
|
||||
player.connection.send(new ClientboundOpenScreenPacket(opened.containerId, opened.getType(), title));
|
||||
player.initMenu(opened);
|
||||
|
||||
return menu.getBukkitView();
|
||||
return opened.getBukkitView();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
plugins {
|
||||
`openinv-base`
|
||||
alias(libs.plugins.paperweight)
|
||||
}
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
|
||||
val paper = candidates.firstOrNull {
|
||||
it.id.let { id ->
|
||||
id is ModuleComponentIdentifier && id.module == "paper-api"
|
||||
}
|
||||
}
|
||||
if (paper != null) {
|
||||
select(paper)
|
||||
}
|
||||
because("module is written for Paper servers")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":openinvapi"))
|
||||
implementation(project(":openinvcommon"))
|
||||
implementation(project(":openinvadaptercommon"))
|
||||
|
||||
paperweight.paperDevBundle("1.21.10-R0.1-SNAPSHOT")
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.lishid.openinv.internal.paper1_21_10;
|
||||
|
||||
import com.lishid.openinv.internal.ISpecialPlayerInventory;
|
||||
import com.lishid.openinv.internal.paper1_21_10.container.OpenInventory;
|
||||
import com.lishid.openinv.internal.paper1_21_10.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.common.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);
|
||||
}
|
||||
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.lishid.openinv.internal.paper1_21_10.container;
|
||||
|
||||
import com.lishid.openinv.internal.common.container.BaseOpenInventory;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.FontDescription;
|
||||
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(new FontDescription.Resource(ResourceLocation.parse("openinv:font/inventory")))
|
||||
.withColor(ChatFormatting.WHITE)));
|
||||
} else {
|
||||
component.append(
|
||||
Component.translatableWithFallback("openinv.container.inventory.other", "")
|
||||
.withStyle(style -> style
|
||||
.withFont(new FontDescription.Resource(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;
|
||||
}
|
||||
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
package com.lishid.openinv.internal.paper1_21_10.player;
|
||||
|
||||
import com.lishid.openinv.internal.common.player.PlayerManager;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class OpenPlayer extends com.lishid.openinv.internal.common.player.OpenPlayer {
|
||||
|
||||
protected OpenPlayer(
|
||||
CraftServer server,
|
||||
ServerPlayer entity,
|
||||
PlayerManager manager
|
||||
) {
|
||||
super(server, entity, manager);
|
||||
}
|
||||
|
||||
@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) {
|
||||
tag.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.lishid.openinv.internal.paper1_21_10.player;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class PlayerManager extends com.lishid.openinv.internal.common.player.PlayerManager {
|
||||
|
||||
public PlayerManager(@NotNull Logger logger) {
|
||||
super(logger);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void injectPlayer(@NotNull MinecraftServer server, @NotNull ServerPlayer player) throws IllegalAccessException {
|
||||
if (bukkitEntity == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
bukkitEntity.setAccessible(true);
|
||||
|
||||
bukkitEntity.set(player, new OpenPlayer(server.server, player, this));
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -14,7 +14,7 @@ public class OpenEnderChest extends com.lishid.openinv.internal.common.container
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable AbstractContainerMenu createMenu(
|
||||
public @Nullable OpenEnderChestMenu createMenu(
|
||||
net.minecraft.world.entity.player.Player player,
|
||||
int i,
|
||||
boolean viewOnly
|
||||
|
||||
+2
-2
@@ -1,5 +1,6 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.container;
|
||||
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import com.lishid.openinv.internal.common.container.slot.ContentCrafting;
|
||||
import com.lishid.openinv.internal.common.container.slot.ContentCursor;
|
||||
import com.lishid.openinv.internal.common.container.slot.ContentDrop;
|
||||
@@ -16,7 +17,6 @@ import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
@@ -181,7 +181,7 @@ public class OpenInventory extends com.lishid.openinv.internal.paper1_21_8.conta
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable AbstractContainerMenu createMenu(Player player, int i, boolean viewOnly) {
|
||||
public @Nullable OpenChestMenu<?> createMenu(Player player, int i, boolean viewOnly) {
|
||||
if (player instanceof ServerPlayer serverPlayer) {
|
||||
return new OpenInventoryMenu(this, serverPlayer, i, viewOnly);
|
||||
}
|
||||
|
||||
-467
@@ -1,467 +0,0 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.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.common.container.bukkit.OpenDummyInventory;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotPlaceholder;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.ChestMenu;
|
||||
import net.minecraft.world.inventory.ClickType;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
import net.minecraft.world.inventory.ContainerListener;
|
||||
import net.minecraft.world.inventory.ContainerSynchronizer;
|
||||
import net.minecraft.world.inventory.DataSlot;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.bukkit.craftbukkit.inventory.CraftInventoryView;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An extension of {@link AbstractContainerMenu} that supports {@link SlotPlaceholder placeholders}.
|
||||
*/
|
||||
@SuppressWarnings("HidingField")
|
||||
public abstract class OpenChestMenu<T extends Container & ISpecialInventory & InternalOwned<ServerPlayer>>
|
||||
extends AbstractContainerMenu {
|
||||
|
||||
protected static final int BOTTOM_INVENTORY_SIZE = 36;
|
||||
|
||||
protected final T container;
|
||||
protected final ServerPlayer viewer;
|
||||
protected final boolean viewOnly;
|
||||
protected final boolean ownContainer;
|
||||
protected final int topSize;
|
||||
private CraftInventoryView<OpenChestMenu<T>, Inventory> bukkitEntity;
|
||||
// Syncher fields
|
||||
private @Nullable ContainerSynchronizer synchronizer;
|
||||
private final List<DataSlot> dataSlots = new ArrayList<>();
|
||||
private final IntList remoteDataSlots = new IntArrayList();
|
||||
private final List<ContainerListener> containerListeners = new ArrayList<>();
|
||||
private ItemStack remoteCarried = ItemStack.EMPTY;
|
||||
private boolean suppressRemoteUpdates;
|
||||
|
||||
protected OpenChestMenu(
|
||||
@NotNull MenuType<ChestMenu> type,
|
||||
int containerCounter,
|
||||
@NotNull T container,
|
||||
@NotNull ServerPlayer viewer,
|
||||
boolean viewOnly
|
||||
) {
|
||||
super(type, containerCounter);
|
||||
this.container = container;
|
||||
this.viewer = viewer;
|
||||
this.viewOnly = viewOnly;
|
||||
ownContainer = container.getOwnerHandle().equals(viewer);
|
||||
topSize = getTopSize(viewer);
|
||||
|
||||
preSlotSetup();
|
||||
|
||||
int upperRows = topSize / 9;
|
||||
// View's upper inventory - our container
|
||||
for (int row = 0; row < upperRows; ++row) {
|
||||
for (int col = 0; col < 9; ++col) {
|
||||
// x and y for client purposes, but hey, we're thorough here.
|
||||
// Adapted from net.minecraft.world.inventory.ChestMenu
|
||||
int x = 8 + col * 18;
|
||||
int y = 18 + row * 18;
|
||||
int index = row * 9 + col;
|
||||
|
||||
// Guard against weird inventory sizes.
|
||||
if (index >= container.getContainerSize()) {
|
||||
addSlot(new SlotViewOnly(container, index, x, y));
|
||||
continue;
|
||||
}
|
||||
|
||||
Slot slot = getUpperSlot(index, x, y);
|
||||
|
||||
addSlot(slot);
|
||||
}
|
||||
}
|
||||
|
||||
// View's lower inventory - viewer inventory
|
||||
int playerInvPad = (upperRows - 4) * 18;
|
||||
for (int row = 0; row < 3; ++row) {
|
||||
for (int col = 0; col < 9; ++col) {
|
||||
int x = 8 + col * 18;
|
||||
int y = playerInvPad + row * 18 + 103;
|
||||
addSlot(new Slot(viewer.getInventory(), row * 9 + col + 9, x, y));
|
||||
}
|
||||
}
|
||||
// Hotbar
|
||||
for (int col = 0; col < 9; ++col) {
|
||||
int x = 8 + col * 18;
|
||||
int y = playerInvPad + 161;
|
||||
addSlot(new Slot(viewer.getInventory(), col, x, y));
|
||||
}
|
||||
}
|
||||
|
||||
protected void preSlotSetup() {
|
||||
}
|
||||
|
||||
protected @NotNull Slot getUpperSlot(int index, int x, int y) {
|
||||
Slot slot = new Slot(container, index, x, y);
|
||||
if (viewOnly) {
|
||||
return SlotViewOnly.wrap(slot);
|
||||
}
|
||||
return slot;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final @NotNull CraftInventoryView<OpenChestMenu<T>, Inventory> getBukkitView() {
|
||||
if (bukkitEntity == null) {
|
||||
bukkitEntity = createBukkitEntity();
|
||||
}
|
||||
|
||||
return bukkitEntity;
|
||||
}
|
||||
|
||||
protected @NotNull CraftInventoryView<OpenChestMenu<T>, Inventory> createBukkitEntity() {
|
||||
Inventory top;
|
||||
if (viewOnly) {
|
||||
top = new OpenDummyInventory(container, container.getBukkitType());
|
||||
} else {
|
||||
top = container.getBukkitInventory();
|
||||
}
|
||||
return new CraftInventoryView<>(viewer.getBukkitEntity(), top, this) {
|
||||
@Override
|
||||
public @Nullable Inventory getInventory(int rawSlot) {
|
||||
if (viewOnly) {
|
||||
return null;
|
||||
}
|
||||
return super.getInventory(rawSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int convertSlot(int rawSlot) {
|
||||
if (viewOnly) {
|
||||
return InventoryView.OUTSIDE;
|
||||
}
|
||||
return super.convertSlot(rawSlot);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull InventoryType.SlotType getSlotType(int slot) {
|
||||
if (viewOnly) {
|
||||
return InventoryType.SlotType.OUTSIDE;
|
||||
}
|
||||
return super.getSlotType(slot);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private int getTopSize(ServerPlayer viewer) {
|
||||
MenuType<?> menuType = getType();
|
||||
if (menuType == MenuType.GENERIC_9x1) {
|
||||
return 9;
|
||||
} else if (menuType == MenuType.GENERIC_9x2) {
|
||||
return 18;
|
||||
} else if (menuType == MenuType.GENERIC_9x3) {
|
||||
return 27;
|
||||
} else if (menuType == MenuType.GENERIC_9x4) {
|
||||
return 36;
|
||||
} else if (menuType == MenuType.GENERIC_9x5) {
|
||||
return 45;
|
||||
} else if (menuType == MenuType.GENERIC_9x6) {
|
||||
return 54;
|
||||
}
|
||||
// This is a bit gross, but allows us a safe fallthrough.
|
||||
return menuType.create(-1, viewer.getInventory()).slots.size() - BOTTOM_INVENTORY_SIZE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reimplementation of {@link AbstractContainerMenu#moveItemStackTo(ItemStack, int, int, boolean)} that ignores fake
|
||||
* slots and respects {@link Slot#hasItem()}.
|
||||
*
|
||||
* @param itemStack the stack to quick-move
|
||||
* @param rangeLow the start of the range of slots that can be moved to, inclusive
|
||||
* @param rangeHigh the end of the range of slots that can be moved to, exclusive
|
||||
* @param topDown whether to start at the top of the range or bottom
|
||||
* @return whether the stack was modified as a result of being quick-moved
|
||||
*/
|
||||
@Override
|
||||
protected boolean moveItemStackTo(ItemStack itemStack, int rangeLow, int rangeHigh, boolean topDown) {
|
||||
boolean modified = false;
|
||||
boolean stackable = itemStack.isStackable();
|
||||
Slot firstEmpty = null;
|
||||
|
||||
for (int index = topDown ? rangeHigh - 1 : rangeLow;
|
||||
!itemStack.isEmpty() && (topDown ? index >= rangeLow : index < rangeHigh);
|
||||
index += topDown ? -1 : 1
|
||||
) {
|
||||
Slot slot = slots.get(index);
|
||||
// If the slot cannot be added to, check the next slot.
|
||||
if (slot.isFake() || !slot.mayPlace(itemStack)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (slot.hasItem()) {
|
||||
// If the item isn't stackable, check the next slot.
|
||||
if (!stackable) {
|
||||
continue;
|
||||
}
|
||||
// Otherwise, add as many as we can from our stack to the slot.
|
||||
modified |= addToExistingStack(itemStack, slot);
|
||||
} else {
|
||||
// If this is the first empty slot, keep track of it for later use.
|
||||
if (firstEmpty == null) {
|
||||
firstEmpty = slot;
|
||||
}
|
||||
// If the item isn't stackable, we've located the slot we're adding it to, so we're done.
|
||||
if (!stackable) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the item hasn't been fully added yet, add as many as we can to the first open slot.
|
||||
if (!itemStack.isEmpty() && firstEmpty != null) {
|
||||
firstEmpty.setByPlayer(itemStack.split(Math.min(itemStack.getCount(), firstEmpty.getMaxStackSize(itemStack))));
|
||||
firstEmpty.setChanged();
|
||||
modified = true;
|
||||
}
|
||||
|
||||
return modified;
|
||||
}
|
||||
|
||||
private static boolean addToExistingStack(ItemStack itemStack, Slot slot) {
|
||||
ItemStack existing = slot.getItem();
|
||||
|
||||
// If the items aren't the same, we can't add our item.
|
||||
if (!ItemStack.isSameItemSameComponents(itemStack, existing)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int max = slot.getMaxStackSize(existing);
|
||||
int existingCount = existing.getCount();
|
||||
|
||||
// If the stack is already full, we can't add more.
|
||||
if (existingCount >= max) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int total = existingCount + itemStack.getCount();
|
||||
|
||||
// If the existing item can accept the entirety of our item, we're done!
|
||||
if (total <= max) {
|
||||
itemStack.setCount(0);
|
||||
existing.setCount(total);
|
||||
slot.setChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise, add as many as we can.
|
||||
itemStack.shrink(max - existingCount);
|
||||
existing.setCount(max);
|
||||
slot.setChanged();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clicked(int i, int j, @NotNull ClickType clickType, @NotNull Player player) {
|
||||
if (viewOnly) {
|
||||
if (clickType == ClickType.QUICK_CRAFT) {
|
||||
sendAllDataToRemote();
|
||||
}
|
||||
return;
|
||||
}
|
||||
super.clicked(i, j, clickType, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean stillValid(@NotNull Player player) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Overrides from here on are purely to modify the sync process to send placeholder items.
|
||||
@Override
|
||||
protected @NotNull Slot addSlot(@NotNull Slot slot) {
|
||||
slot.index = this.slots.size();
|
||||
this.slots.add(slot);
|
||||
this.lastSlots.add(ItemStack.EMPTY);
|
||||
this.remoteSlots.add(ItemStack.EMPTY);
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull DataSlot addDataSlot(@NotNull DataSlot dataSlot) {
|
||||
this.dataSlots.add(dataSlot);
|
||||
this.remoteDataSlots.add(0);
|
||||
return dataSlot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDataSlots(ContainerData containerData) {
|
||||
for (int i = 0; i < containerData.getCount(); i++) {
|
||||
this.addDataSlot(DataSlot.forContainer(containerData, i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSlotListener(@NotNull ContainerListener containerListener) {
|
||||
if (!this.containerListeners.contains(containerListener)) {
|
||||
this.containerListeners.add(containerListener);
|
||||
this.broadcastChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSynchronizer(@NotNull ContainerSynchronizer containerSynchronizer) {
|
||||
this.synchronizer = containerSynchronizer;
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAllDataToRemote() {
|
||||
for (int index = 0; index < slots.size(); ++index) {
|
||||
Slot slot = slots.get(index);
|
||||
this.remoteSlots.set(index, (slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem()).copy());
|
||||
}
|
||||
|
||||
remoteCarried = getCarried().copy();
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
this.remoteDataSlots.set(index, this.dataSlots.get(index).get());
|
||||
}
|
||||
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendInitialData(this, this.remoteSlots, this.remoteCarried, this.remoteDataSlots.toIntArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastCarriedItem() {
|
||||
this.remoteCarried = this.getCarried().copy();
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSlotListener(@NotNull ContainerListener containerListener) {
|
||||
this.containerListeners.remove(containerListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastChanges() {
|
||||
for (int index = 0; index < this.slots.size(); ++index) {
|
||||
Slot slot = this.slots.get(index);
|
||||
ItemStack itemstack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
|
||||
Supplier<ItemStack> supplier = Suppliers.memoize(itemstack::copy);
|
||||
this.triggerSlotListeners(index, itemstack, supplier);
|
||||
this.synchronizeSlotToRemote(index, itemstack, supplier);
|
||||
}
|
||||
|
||||
this.synchronizeCarriedToRemote();
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
DataSlot dataSlot = this.dataSlots.get(index);
|
||||
int j = dataSlot.get();
|
||||
if (dataSlot.checkAndClearUpdateFlag()) {
|
||||
this.updateDataSlotListeners(index, j);
|
||||
}
|
||||
|
||||
this.synchronizeDataSlotToRemote(index, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastFullState() {
|
||||
for (int index = 0; index < this.slots.size(); ++index) {
|
||||
ItemStack itemstack = this.slots.get(index).getItem();
|
||||
this.triggerSlotListeners(index, itemstack, itemstack::copy);
|
||||
}
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
DataSlot containerproperty = this.dataSlots.get(index);
|
||||
if (containerproperty.checkAndClearUpdateFlag()) {
|
||||
this.updateDataSlotListeners(index, containerproperty.get());
|
||||
}
|
||||
}
|
||||
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
private void updateDataSlotListeners(int i, int j) {
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.dataChanged(this, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerSlotListeners(int index, ItemStack itemStack, Supplier<ItemStack> supplier) {
|
||||
ItemStack itemStack1 = this.lastSlots.get(index);
|
||||
if (!ItemStack.matches(itemStack1, itemStack)) {
|
||||
ItemStack itemStack2 = supplier.get();
|
||||
this.lastSlots.set(index, itemStack2);
|
||||
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.slotChanged(this, index, itemStack2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeSlotToRemote(int i, ItemStack itemStack, Supplier<ItemStack> supplier) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
ItemStack itemStack1 = this.remoteSlots.get(i);
|
||||
if (!ItemStack.matches(itemStack1, itemStack)) {
|
||||
ItemStack itemstack2 = supplier.get();
|
||||
this.remoteSlots.set(i, itemstack2);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendSlotChange(this, i, itemstack2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeDataSlotToRemote(int index, int value) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
int existing = this.remoteDataSlots.getInt(index);
|
||||
if (existing != value) {
|
||||
this.remoteDataSlots.set(index, value);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendDataChange(this, index, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeCarriedToRemote() {
|
||||
if (!this.suppressRemoteUpdates && !ItemStack.matches(this.getCarried(), this.remoteCarried)) {
|
||||
this.remoteCarried = this.getCarried().copy();
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoteCarried(ItemStack itemstack) {
|
||||
this.remoteCarried = itemstack.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suppressRemoteUpdates() {
|
||||
this.suppressRemoteUpdates = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resumeRemoteUpdates() {
|
||||
this.suppressRemoteUpdates = false;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-2
@@ -1,13 +1,14 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.container.menu;
|
||||
|
||||
import com.lishid.openinv.internal.common.container.OpenEnderChest;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class OpenEnderChestMenu extends OpenChestMenu<OpenEnderChest> {
|
||||
public class OpenEnderChestMenu extends OpenSyncMenu<OpenEnderChest> {
|
||||
|
||||
public OpenEnderChestMenu(
|
||||
@NotNull OpenEnderChest enderChest,
|
||||
@@ -16,7 +17,7 @@ public class OpenEnderChestMenu extends OpenChestMenu<OpenEnderChest> {
|
||||
boolean viewOnly
|
||||
) {
|
||||
super(
|
||||
com.lishid.openinv.internal.common.container.menu.OpenChestMenu.getChestMenuType(enderChest.getContainerSize()),
|
||||
OpenChestMenu.getChestMenuType(enderChest.getContainerSize()),
|
||||
containerId,
|
||||
enderChest,
|
||||
viewer,
|
||||
|
||||
+3
-2
@@ -2,6 +2,7 @@ package com.lishid.openinv.internal.paper1_21_4.container.menu;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.lishid.openinv.internal.common.container.bukkit.OpenDummyPlayerInventory;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import com.lishid.openinv.internal.common.container.slot.ContentDrop;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotViewOnly;
|
||||
import com.lishid.openinv.internal.paper1_21_4.container.OpenInventory;
|
||||
@@ -23,7 +24,7 @@ import org.bukkit.inventory.InventoryView;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class OpenInventoryMenu extends OpenChestMenu<OpenInventory> {
|
||||
public class OpenInventoryMenu extends OpenSyncMenu<OpenInventory> {
|
||||
|
||||
private int offset;
|
||||
|
||||
@@ -39,7 +40,7 @@ public class OpenInventoryMenu extends OpenChestMenu<OpenInventory> {
|
||||
size = ((int) Math.ceil(size / 9.0)) * 9;
|
||||
}
|
||||
|
||||
return com.lishid.openinv.internal.common.container.menu.OpenChestMenu.getChestMenuType(size);
|
||||
return OpenChestMenu.getChestMenuType(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+229
@@ -0,0 +1,229 @@
|
||||
package com.lishid.openinv.internal.paper1_21_4.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.common.container.menu.OpenChestMenu;
|
||||
import com.lishid.openinv.internal.common.container.slot.SlotPlaceholder;
|
||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||
import it.unimi.dsi.fastutil.ints.IntList;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.ChestMenu;
|
||||
import net.minecraft.world.inventory.ContainerData;
|
||||
import net.minecraft.world.inventory.ContainerListener;
|
||||
import net.minecraft.world.inventory.ContainerSynchronizer;
|
||||
import net.minecraft.world.inventory.DataSlot;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* An extension of {@link AbstractContainerMenu} that supports {@link SlotPlaceholder placeholders}.
|
||||
*/
|
||||
@SuppressWarnings("HidingField")
|
||||
public abstract class OpenSyncMenu<T extends Container & ISpecialInventory & InternalOwned<ServerPlayer>>
|
||||
extends OpenChestMenu<T> {
|
||||
|
||||
// Syncher fields
|
||||
private @Nullable ContainerSynchronizer synchronizer;
|
||||
private final List<DataSlot> dataSlots = new ArrayList<>();
|
||||
private final IntList remoteDataSlots = new IntArrayList();
|
||||
private final List<ContainerListener> containerListeners = new ArrayList<>();
|
||||
private ItemStack remoteCarried = ItemStack.EMPTY;
|
||||
private boolean suppressRemoteUpdates;
|
||||
|
||||
protected OpenSyncMenu(
|
||||
@NotNull MenuType<ChestMenu> type,
|
||||
int containerCounter,
|
||||
@NotNull T container,
|
||||
@NotNull ServerPlayer viewer,
|
||||
boolean viewOnly
|
||||
) {
|
||||
super(type, containerCounter, container, viewer, viewOnly);
|
||||
}
|
||||
|
||||
// Overrides from here on are purely to modify the sync process to send placeholder items.
|
||||
@Override
|
||||
protected @NotNull Slot addSlot(@NotNull Slot slot) {
|
||||
slot.index = this.slots.size();
|
||||
this.slots.add(slot);
|
||||
this.lastSlots.add(ItemStack.EMPTY);
|
||||
this.remoteSlots.add(ItemStack.EMPTY);
|
||||
return slot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull DataSlot addDataSlot(@NotNull DataSlot dataSlot) {
|
||||
this.dataSlots.add(dataSlot);
|
||||
this.remoteDataSlots.add(0);
|
||||
return dataSlot;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDataSlots(ContainerData containerData) {
|
||||
for (int i = 0; i < containerData.getCount(); i++) {
|
||||
this.addDataSlot(DataSlot.forContainer(containerData, i));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSlotListener(@NotNull ContainerListener containerListener) {
|
||||
if (!this.containerListeners.contains(containerListener)) {
|
||||
this.containerListeners.add(containerListener);
|
||||
this.broadcastChanges();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSynchronizer(@NotNull ContainerSynchronizer containerSynchronizer) {
|
||||
this.synchronizer = containerSynchronizer;
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendAllDataToRemote() {
|
||||
for (int index = 0; index < slots.size(); ++index) {
|
||||
Slot slot = slots.get(index);
|
||||
this.remoteSlots.set(index, (slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem()).copy());
|
||||
}
|
||||
|
||||
remoteCarried = getCarried().copy();
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
this.remoteDataSlots.set(index, this.dataSlots.get(index).get());
|
||||
}
|
||||
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendInitialData(this, this.remoteSlots, this.remoteCarried, this.remoteDataSlots.toIntArray());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastCarriedItem() {
|
||||
this.remoteCarried = this.getCarried().copy();
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSlotListener(@NotNull ContainerListener containerListener) {
|
||||
this.containerListeners.remove(containerListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastChanges() {
|
||||
for (int index = 0; index < this.slots.size(); ++index) {
|
||||
Slot slot = this.slots.get(index);
|
||||
ItemStack itemstack = slot instanceof SlotPlaceholder placeholder ? placeholder.getOrDefault() : slot.getItem();
|
||||
Supplier<ItemStack> supplier = Suppliers.memoize(itemstack::copy);
|
||||
this.triggerSlotListeners(index, itemstack, supplier);
|
||||
this.synchronizeSlotToRemote(index, itemstack, supplier);
|
||||
}
|
||||
|
||||
this.synchronizeCarriedToRemote();
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
DataSlot dataSlot = this.dataSlots.get(index);
|
||||
int j = dataSlot.get();
|
||||
if (dataSlot.checkAndClearUpdateFlag()) {
|
||||
this.updateDataSlotListeners(index, j);
|
||||
}
|
||||
|
||||
this.synchronizeDataSlotToRemote(index, j);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void broadcastFullState() {
|
||||
for (int index = 0; index < this.slots.size(); ++index) {
|
||||
ItemStack itemstack = this.slots.get(index).getItem();
|
||||
this.triggerSlotListeners(index, itemstack, itemstack::copy);
|
||||
}
|
||||
|
||||
for (int index = 0; index < this.dataSlots.size(); ++index) {
|
||||
DataSlot containerproperty = this.dataSlots.get(index);
|
||||
if (containerproperty.checkAndClearUpdateFlag()) {
|
||||
this.updateDataSlotListeners(index, containerproperty.get());
|
||||
}
|
||||
}
|
||||
|
||||
this.sendAllDataToRemote();
|
||||
}
|
||||
|
||||
private void updateDataSlotListeners(int i, int j) {
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.dataChanged(this, i, j);
|
||||
}
|
||||
}
|
||||
|
||||
private void triggerSlotListeners(int index, ItemStack itemStack, Supplier<ItemStack> supplier) {
|
||||
ItemStack itemStack1 = this.lastSlots.get(index);
|
||||
if (!ItemStack.matches(itemStack1, itemStack)) {
|
||||
ItemStack itemStack2 = supplier.get();
|
||||
this.lastSlots.set(index, itemStack2);
|
||||
|
||||
for (ContainerListener containerListener : this.containerListeners) {
|
||||
containerListener.slotChanged(this, index, itemStack2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeSlotToRemote(int i, ItemStack itemStack, Supplier<ItemStack> supplier) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
ItemStack itemStack1 = this.remoteSlots.get(i);
|
||||
if (!ItemStack.matches(itemStack1, itemStack)) {
|
||||
ItemStack itemstack2 = supplier.get();
|
||||
this.remoteSlots.set(i, itemstack2);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendSlotChange(this, i, itemstack2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeDataSlotToRemote(int index, int value) {
|
||||
if (!this.suppressRemoteUpdates) {
|
||||
int existing = this.remoteDataSlots.getInt(index);
|
||||
if (existing != value) {
|
||||
this.remoteDataSlots.set(index, value);
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendDataChange(this, index, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void synchronizeCarriedToRemote() {
|
||||
if (!this.suppressRemoteUpdates && !ItemStack.matches(this.getCarried(), this.remoteCarried)) {
|
||||
this.remoteCarried = this.getCarried().copy();
|
||||
if (this.synchronizer != null) {
|
||||
this.synchronizer.sendCarriedChange(this, this.remoteCarried);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRemoteCarried(ItemStack itemstack) {
|
||||
this.remoteCarried = itemstack.copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void suppressRemoteUpdates() {
|
||||
this.suppressRemoteUpdates = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resumeRemoteUpdates() {
|
||||
this.suppressRemoteUpdates = false;
|
||||
}
|
||||
|
||||
}
|
||||
+13
-21
@@ -1,16 +1,13 @@
|
||||
package com.lishid.openinv.internal.paper1_21_5.player;
|
||||
|
||||
import com.lishid.openinv.event.OpenEvents;
|
||||
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class OpenPlayer extends BaseOpenPlayer {
|
||||
@@ -20,12 +17,7 @@ public class OpenPlayer extends BaseOpenPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveData() {
|
||||
if (OpenEvents.saveCancelled(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPlayer player = this.getHandle();
|
||||
protected void trySave(ServerPlayer player) {
|
||||
// See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman)
|
||||
try {
|
||||
PlayerDataStorage worldNBTStorage = player.server.getPlayerList().playerIo;
|
||||
@@ -35,20 +27,20 @@ public class OpenPlayer extends BaseOpenPlayer {
|
||||
|
||||
playerData = player.saveWithoutId(playerData);
|
||||
|
||||
if (oldData != null) {
|
||||
// Revert certain special data values when offline.
|
||||
revertSpecialValues(playerData, oldData);
|
||||
}
|
||||
|
||||
Path playerDataDir = worldNBTStorage.getPlayerDir().toPath();
|
||||
Path tempFile = Files.createTempFile(playerDataDir, player.getStringUUID() + "-", ".dat");
|
||||
NbtIo.writeCompressed(playerData, tempFile);
|
||||
Path dataFile = playerDataDir.resolve(player.getStringUUID() + ".dat");
|
||||
Path backupFile = playerDataDir.resolve(player.getStringUUID() + ".dat_old");
|
||||
Util.safeReplaceFile(dataFile, tempFile, backupFile);
|
||||
saveSafe(player, oldData, playerData, worldNBTStorage);
|
||||
} catch (Exception e) {
|
||||
LogUtils.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
tag.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
+7
-1
@@ -1,6 +1,7 @@
|
||||
package com.lishid.openinv.internal.paper1_21_8.container;
|
||||
|
||||
import com.lishid.openinv.internal.common.container.BaseOpenInventory;
|
||||
import com.lishid.openinv.internal.common.container.menu.OpenChestMenu;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
@@ -17,7 +18,7 @@ public class OpenInventory extends BaseOpenInventory {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component getTitle(@Nullable ServerPlayer viewer) {
|
||||
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)) {
|
||||
@@ -33,6 +34,11 @@ public class OpenInventory extends BaseOpenInventory {
|
||||
.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"))
|
||||
|
||||
+15
-23
@@ -1,20 +1,17 @@
|
||||
package com.lishid.openinv.internal.paper1_21_8.player;
|
||||
|
||||
import com.lishid.openinv.event.OpenEvents;
|
||||
import com.lishid.openinv.internal.common.player.BaseOpenPlayer;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.ProblemReporter;
|
||||
import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||
import net.minecraft.world.level.storage.TagValueOutput;
|
||||
import net.minecraft.world.level.storage.ValueOutput;
|
||||
import org.bukkit.craftbukkit.CraftServer;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class OpenPlayer extends BaseOpenPlayer {
|
||||
@@ -28,39 +25,34 @@ public class OpenPlayer extends BaseOpenPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveData() {
|
||||
if (OpenEvents.saveCancelled(this)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ServerPlayer player = this.getHandle();
|
||||
protected void trySave(ServerPlayer player) {
|
||||
Logger logger = LogUtils.getLogger();
|
||||
// See net.minecraft.world.level.storage.PlayerDataStorage#save(EntityHuman)
|
||||
try (ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(player.problemPath(), logger)) {
|
||||
PlayerDataStorage worldNBTStorage = server.getServer().getPlayerList().playerIo;
|
||||
PlayerDataStorage worldNbtStorage = server.getServer().getPlayerList().playerIo;
|
||||
|
||||
CompoundTag oldData = isOnline()
|
||||
? null
|
||||
: worldNBTStorage.load(player.getName().getString(), player.getStringUUID(), scopedCollector).orElse(null);
|
||||
: worldNbtStorage.load(player.getName().getString(), player.getStringUUID(), scopedCollector).orElse(null);
|
||||
CompoundTag playerData = getWritableTag(oldData);
|
||||
|
||||
ValueOutput valueOutput = TagValueOutput.createWrappingWithContext(scopedCollector, player.registryAccess(), playerData);
|
||||
player.saveWithoutId(valueOutput);
|
||||
|
||||
if (oldData != null) {
|
||||
// Revert certain special data values when offline.
|
||||
revertSpecialValues(playerData, oldData);
|
||||
}
|
||||
|
||||
Path playerDataDir = worldNBTStorage.getPlayerDir().toPath();
|
||||
Path tempFile = Files.createTempFile(playerDataDir, player.getStringUUID() + "-", ".dat");
|
||||
NbtIo.writeCompressed(playerData, tempFile);
|
||||
Path dataFile = playerDataDir.resolve(player.getStringUUID() + ".dat");
|
||||
Path backupFile = playerDataDir.resolve(player.getStringUUID() + ".dat_old");
|
||||
Util.safeReplaceFile(dataFile, tempFile, backupFile);
|
||||
saveSafe(player, oldData, playerData, worldNbtStorage);
|
||||
} catch (Exception e) {
|
||||
LogUtils.getLogger().warn("Failed to save player data for {}: {}", player.getScoreboardName(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@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) {
|
||||
tag.remove(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,9 +10,9 @@ plugins {
|
||||
apply<SpigotSetup>()
|
||||
apply<SpigotReobf>()
|
||||
|
||||
val spigotVer = "1.21.10-R0.1-SNAPSHOT"
|
||||
val spigotVer = "1.21.11-R0.1-SNAPSHOT"
|
||||
// Used by common adapter to relocate Craftbukkit classes to a versioned package.
|
||||
rootProject.extra["craftbukkitPackage"] = "v1_21_R6"
|
||||
rootProject.extra["craftbukkitPackage"] = "v1_21_R7"
|
||||
|
||||
configurations.all {
|
||||
resolutionStrategy.capabilitiesResolution.withCapability("org.spigotmc:spigot-api") {
|
||||
|
||||
+6
-6
@@ -1,11 +1,11 @@
|
||||
package com.lishid.openinv.internal.reobf.container.bukkit;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.lishid.openinv.internal.reobf.container.OpenInventory;
|
||||
import com.lishid.openinv.internal.reobf.container.BaseOpenInventory;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.world.entity.player.Inventory;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftInventory;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftInventory;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
@@ -15,13 +15,13 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class OpenPlayerInventory extends CraftInventory implements PlayerInventory {
|
||||
|
||||
public OpenPlayerInventory(@NotNull OpenInventory inventory) {
|
||||
public OpenPlayerInventory(@NotNull BaseOpenInventory inventory) {
|
||||
super(inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull OpenInventory getInventory() {
|
||||
return (OpenInventory) super.getInventory();
|
||||
public @NotNull BaseOpenInventory getInventory() {
|
||||
return (BaseOpenInventory) super.getInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+2
-2
@@ -6,8 +6,8 @@ import net.minecraft.world.Container;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.inventory.Slot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.CraftEquipmentSlot;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.CraftEquipmentSlot;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.inventory.CraftItemStack;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
+3
-3
@@ -2,7 +2,6 @@ package com.lishid.openinv.internal.reobf.player;
|
||||
|
||||
import com.lishid.openinv.event.OpenEvents;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.nbt.NumericTag;
|
||||
@@ -10,11 +9,12 @@ import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.util.ProblemReporter;
|
||||
import net.minecraft.util.Util;
|
||||
import net.minecraft.world.level.storage.PlayerDataStorage;
|
||||
import net.minecraft.world.level.storage.TagValueOutput;
|
||||
import net.minecraft.world.level.storage.ValueOutput;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer;
|
||||
import org.jetbrains.annotations.Contract;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
+13
-12
@@ -3,6 +3,7 @@ package com.lishid.openinv.internal.reobf.player;
|
||||
import com.lishid.openinv.internal.ISpecialInventory;
|
||||
import com.lishid.openinv.internal.reobf.container.OpenEnderChest;
|
||||
import com.lishid.openinv.internal.reobf.container.OpenInventory;
|
||||
import com.lishid.openinv.internal.reobf.container.menu.OpenChestMenu;
|
||||
import com.lishid.openinv.util.JulLoggerAdapter;
|
||||
import com.mojang.authlib.GameProfile;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
@@ -23,9 +24,9 @@ import net.minecraft.world.level.storage.ValueInput;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_21_R6.event.CraftEventFactory;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.CraftServer;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.entity.CraftPlayer;
|
||||
import org.bukkit.craftbukkit.v1_21_R7.event.CraftEventFactory;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -197,14 +198,14 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
|
||||
}
|
||||
|
||||
// See net.minecraft.server.level.ServerPlayer#openMenu(MenuProvider)
|
||||
AbstractContainerMenu menu;
|
||||
OpenChestMenu<?> menu;
|
||||
Component title;
|
||||
if (inventory instanceof OpenInventory playerInv) {
|
||||
menu = playerInv.createMenu(player, player.nextContainerCounter(), viewOnly);
|
||||
title = playerInv.getTitle(player);
|
||||
title = playerInv.getTitle(player, menu);
|
||||
} else if (inventory instanceof OpenEnderChest enderChest) {
|
||||
menu = enderChest.createMenu(player, player.nextContainerCounter(), viewOnly);
|
||||
title = enderChest.getTitle();
|
||||
title = enderChest.getTitle(menu);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -219,18 +220,18 @@ public class PlayerManager implements com.lishid.openinv.internal.PlayerManager
|
||||
// resulting in a title change but no other state modifications (like cursor position).
|
||||
menu.setTitle(title);
|
||||
|
||||
menu = CraftEventFactory.callInventoryOpenEvent(player, menu, false);
|
||||
AbstractContainerMenu opened = CraftEventFactory.callInventoryOpenEvent(player, menu, false);
|
||||
|
||||
// Menu is null if event is cancelled.
|
||||
if (menu == null) {
|
||||
if (opened == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
player.containerMenu = menu;
|
||||
player.connection.send(new ClientboundOpenScreenPacket(menu.containerId, menu.getType(), menu.getTitle()));
|
||||
player.initMenu(menu);
|
||||
player.containerMenu = opened;
|
||||
player.connection.send(new ClientboundOpenScreenPacket(opened.containerId, opened.getType(), opened.getTitle()));
|
||||
player.initMenu(opened);
|
||||
|
||||
return menu.getBukkitView();
|
||||
return opened.getBukkitView();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,6 +13,7 @@ dependencies {
|
||||
implementation(project(":openinvapi"))
|
||||
implementation(project(":openinvcommon"))
|
||||
implementation(project(":openinvadaptercommon"))
|
||||
implementation(project(":openinvadapterpaper1_21_10"))
|
||||
implementation(project(":openinvadapterpaper1_21_8"))
|
||||
implementation(project(":openinvadapterpaper1_21_5"))
|
||||
implementation(project(":openinvadapterpaper1_21_4"))
|
||||
|
||||
@@ -244,6 +244,7 @@ public class OpenInv extends FoliaWrappedJavaPlugin implements IOpenInv {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated(forRemoval = true)
|
||||
public @Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) {
|
||||
Permissions edit = null;
|
||||
HumanEntity target = inventory.getPlayer();
|
||||
@@ -256,10 +257,12 @@ public class OpenInv extends FoliaWrappedJavaPlugin implements IOpenInv {
|
||||
|
||||
boolean viewOnly = edit != null && !edit.hasPermission(player);
|
||||
|
||||
if (ownContainer || (viewOnly && config.getAccessEqualMode() != AccessEqualMode.DENY)) {
|
||||
if (ownContainer) {
|
||||
return this.accessor.openInventory(player, inventory, viewOnly);
|
||||
}
|
||||
|
||||
AccessEqualMode accessMode = AccessEqualMode.getByPerm(player, config);
|
||||
|
||||
for (int level = 4; level > 0; --level) {
|
||||
String permission = "openinv.access.level." + level;
|
||||
// If the target doesn't have this access level...
|
||||
@@ -273,17 +276,22 @@ public class OpenInv extends FoliaWrappedJavaPlugin implements IOpenInv {
|
||||
}
|
||||
|
||||
// If the viewer doesn't have an equal access level or equal access is a denial, deny.
|
||||
if (!player.hasPermission(permission) || config.getAccessEqualMode() == AccessEqualMode.DENY) {
|
||||
if (!player.hasPermission(permission) || accessMode == AccessEqualMode.DENY) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Since this is a tie, setting decides view state.
|
||||
if (config.getAccessEqualMode() == AccessEqualMode.VIEW) {
|
||||
if (accessMode == AccessEqualMode.VIEW) {
|
||||
viewOnly = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return openInventory(player, inventory, viewOnly);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory, boolean viewOnly) {
|
||||
return this.accessor.openInventory(player, inventory, viewOnly);
|
||||
}
|
||||
|
||||
|
||||
@@ -87,10 +87,11 @@ public class ClearInvCommand extends PlayerLookupCommand {
|
||||
@Override
|
||||
protected void handle(
|
||||
@NotNull CommandSender sender,
|
||||
@NotNull Player onlineTarget,
|
||||
@NotNull PlayerAccess playerAccess,
|
||||
boolean accessInv,
|
||||
@NotNull String @NotNull [] args
|
||||
) {
|
||||
Player onlineTarget = playerAccess.player();
|
||||
// Create the inventory
|
||||
final ISpecialInventory inv;
|
||||
try {
|
||||
|
||||
@@ -151,11 +151,12 @@ public class OpenInvCommand extends PlayerLookupCommand {
|
||||
@Override
|
||||
protected void handle(
|
||||
@NotNull CommandSender sender,
|
||||
@NotNull Player target,
|
||||
@NotNull PlayerAccess playerAccess,
|
||||
boolean accessInv,
|
||||
@NotNull String @NotNull [] args
|
||||
) {
|
||||
Player player = (Player) sender;
|
||||
Player target = playerAccess.player();
|
||||
if (!config.doesNoArgsOpenSelf()) {
|
||||
// Record the target
|
||||
(accessInv ? this.openInvHistory : this.openEnderHistory).put(player, target.getUniqueId().toString());
|
||||
@@ -172,7 +173,7 @@ public class OpenInvCommand extends PlayerLookupCommand {
|
||||
}
|
||||
|
||||
// Open the inventory
|
||||
plugin.openInventory(player, inv);
|
||||
plugin.openInventory(player, inv, playerAccess.viewOnly());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -79,7 +79,7 @@ public abstract class PlayerLookupCommand implements TabExecutor {
|
||||
}
|
||||
|
||||
// Perform access checks and load target if necessary.
|
||||
Player onlineTarget = access(sender, target, accessInv);
|
||||
PlayerAccess onlineTarget = access(sender, target, accessInv);
|
||||
|
||||
if (onlineTarget != null) {
|
||||
handle(sender, onlineTarget, accessInv, args);
|
||||
@@ -135,7 +135,11 @@ public abstract class PlayerLookupCommand implements TabExecutor {
|
||||
* @param invPerms {@code true} to use inventory permissions, {@code false} for ender chest
|
||||
* @return the {@link Player} loaded or {@code null} if target is not accessible
|
||||
*/
|
||||
protected @Nullable Player access(@NotNull CommandSender sender, @NotNull OfflinePlayer target, boolean invPerms) {
|
||||
protected @Nullable PlayerAccess access(
|
||||
@NotNull CommandSender sender,
|
||||
@NotNull OfflinePlayer target,
|
||||
boolean invPerms
|
||||
) {
|
||||
// Attempt to load online player dependent on permissions and configuration.
|
||||
Player onlineTarget = accessAsPlayer(sender, target);
|
||||
|
||||
@@ -144,11 +148,11 @@ public abstract class PlayerLookupCommand implements TabExecutor {
|
||||
}
|
||||
|
||||
// Permissions checks.
|
||||
if (deniedCommand(sender, onlineTarget, invPerms) || deniedAccess(sender, onlineTarget)) {
|
||||
if (deniedCommand(sender, onlineTarget, invPerms)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return onlineTarget;
|
||||
return accessGeneralized(sender, onlineTarget, invPerms);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -203,30 +207,33 @@ public abstract class PlayerLookupCommand implements TabExecutor {
|
||||
);
|
||||
|
||||
/**
|
||||
* Check for a lack of generalized permissions for accessing the target.
|
||||
* Check for generalized permissions for accessing the target.
|
||||
* By default, this is access levels and cross-world restrictions.
|
||||
*
|
||||
* @param sender the {@link CommandSender} attempting access
|
||||
* @param onlineTarget the {@link Player} being targeted by the command
|
||||
* @return {@code true} if the sender does not have access to the target
|
||||
* @param invPerms {@code true} to use inventory permissions, {@code false} for ender chest
|
||||
* @return a {@link PlayerAccess} containing the accessed player and view mode, or {@code null} if denied
|
||||
*/
|
||||
protected boolean deniedAccess(@NotNull CommandSender sender, @NotNull Player onlineTarget) {
|
||||
if (sender.equals(onlineTarget)) {
|
||||
return false;
|
||||
protected @Nullable PlayerAccess accessGeneralized(
|
||||
@NotNull CommandSender sender,
|
||||
@NotNull Player onlineTarget,
|
||||
boolean invPerms
|
||||
) {
|
||||
|
||||
boolean ownContainer = sender.equals(onlineTarget);
|
||||
Permissions edit;
|
||||
if (invPerms) {
|
||||
edit = ownContainer ? Permissions.INVENTORY_EDIT_SELF : Permissions.INVENTORY_EDIT_OTHER;
|
||||
} else {
|
||||
edit = ownContainer ? Permissions.ENDERCHEST_EDIT_SELF : Permissions.ENDERCHEST_EDIT_OTHER;
|
||||
}
|
||||
|
||||
// Protected check
|
||||
for (int level = 4; level > 0; --level) {
|
||||
String permission = "openinv.access.level." + level;
|
||||
if (onlineTarget.hasPermission(permission)
|
||||
&& (!sender.hasPermission(permission) || config.getAccessEqualMode() == AccessEqualMode.DENY)) {
|
||||
lang.sendMessage(
|
||||
sender,
|
||||
"messages.error.permissionExempt",
|
||||
new Replacement("%target%", onlineTarget.getDisplayName())
|
||||
);
|
||||
return true;
|
||||
}
|
||||
boolean viewOnly = !edit.hasPermission(sender);
|
||||
|
||||
if (ownContainer) {
|
||||
// Skip other access checks for self.
|
||||
return new PlayerAccess(onlineTarget, viewOnly);
|
||||
}
|
||||
|
||||
// Crossworld check
|
||||
@@ -238,10 +245,41 @@ public abstract class PlayerLookupCommand implements TabExecutor {
|
||||
"messages.error.permissionCrossWorld",
|
||||
new Replacement("%target%", onlineTarget.getDisplayName())
|
||||
);
|
||||
return true;
|
||||
return null;
|
||||
}
|
||||
|
||||
return false;
|
||||
AccessEqualMode accessMode = AccessEqualMode.getByPerm(sender, config);
|
||||
|
||||
for (int level = 4; level > 0; --level) {
|
||||
String permission = "openinv.access.level." + level;
|
||||
// If the target doesn't have this access level...
|
||||
if (!onlineTarget.hasPermission(permission)) {
|
||||
// If the viewer does have the access level, all good.
|
||||
if (sender.hasPermission(permission)) {
|
||||
break;
|
||||
}
|
||||
// Otherwise check next access level.
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the viewer doesn't have an equal access level or equal access is a denial, deny.
|
||||
if (!sender.hasPermission(permission) || accessMode == AccessEqualMode.DENY) {
|
||||
lang.sendMessage(
|
||||
sender,
|
||||
"messages.error.permissionExempt",
|
||||
new Replacement("%target%", onlineTarget.getDisplayName())
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Since this is a tie, setting decides view state.
|
||||
if (accessMode == AccessEqualMode.VIEW) {
|
||||
viewOnly = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return new PlayerAccess(onlineTarget, viewOnly);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,7 +292,7 @@ public abstract class PlayerLookupCommand implements TabExecutor {
|
||||
*/
|
||||
protected abstract void handle(
|
||||
@NotNull CommandSender sender,
|
||||
@NotNull Player target,
|
||||
@NotNull PlayerAccess target,
|
||||
boolean accessInv,
|
||||
@NotNull String @NotNull [] args
|
||||
);
|
||||
@@ -273,4 +311,6 @@ public abstract class PlayerLookupCommand implements TabExecutor {
|
||||
return TabCompleter.completeOnlinePlayer(sender, args[0]);
|
||||
}
|
||||
|
||||
protected record PlayerAccess(Player player, boolean viewOnly) {}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.lishid.openinv.util;
|
||||
|
||||
import com.lishid.openinv.util.config.Config;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -20,4 +22,17 @@ public enum AccessEqualMode {
|
||||
};
|
||||
}
|
||||
|
||||
public static @NotNull AccessEqualMode getByPerm(@NotNull Permissible permissible, @NotNull Config config) {
|
||||
if (Permissions.ACCESS_EQUAL_EDIT.hasPermission(permissible)) {
|
||||
return AccessEqualMode.ALLOW;
|
||||
}
|
||||
if (Permissions.ACCESS_EQUAL_VIEW.hasPermission(permissible)) {
|
||||
return AccessEqualMode.VIEW;
|
||||
}
|
||||
if (Permissions.ACCESS_EQUAL_DENY.hasPermission(permissible)) {
|
||||
return AccessEqualMode.DENY;
|
||||
}
|
||||
return config.getAccessEqualMode();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -64,7 +64,7 @@ public class InternalAccessor {
|
||||
}
|
||||
|
||||
private @Nullable Accessor getAccessor(@NotNull Logger logger, @NotNull LanguageManager lang) {
|
||||
Version maxSupported = Version.of(1, 21, 10);
|
||||
Version maxSupported = Version.of(1, 21, 11);
|
||||
Version minSupported = Version.of(1, 21, 1);
|
||||
|
||||
// Ensure version is in supported range.
|
||||
@@ -84,10 +84,13 @@ public class InternalAccessor {
|
||||
}
|
||||
|
||||
// Paper or a Paper fork, can use Mojang-mapped internals.
|
||||
if (BukkitVersions.MINECRAFT.lessThanOrEqual(maxSupported)
|
||||
&& BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 9))) { // 1.21.9, 1.21.10
|
||||
if (BukkitVersions.MINECRAFT.equals(maxSupported)) { // 1.21.11
|
||||
return new com.lishid.openinv.internal.common.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);
|
||||
}
|
||||
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 21, 8))
|
||||
&& BukkitVersions.MINECRAFT.greaterThanOrEqual(Version.of(1, 21, 6))) { // 1.21.6, 1.21.7, 1.21.8
|
||||
return new com.lishid.openinv.internal.paper1_21_8.InternalAccessor(logger, lang);
|
||||
@@ -204,7 +207,10 @@ public class InternalAccessor {
|
||||
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.13";
|
||||
}
|
||||
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 21, 9))) {
|
||||
return "Unsupported; upgrade to 1.21.10: https://github.com/Jikoo/OpenInv/releases";
|
||||
return "Unsupported; upgrade to 1.21.10: https://github.com/Jikoo/OpenInv/releases/tag/5.1.15";
|
||||
}
|
||||
if (BukkitVersions.MINECRAFT.lessThanOrEqual(Version.of(1, 21, 10))) {
|
||||
return "https://github.com/Jikoo/OpenInv/releases/tag/5.1.15";
|
||||
}
|
||||
|
||||
return "https://github.com/Jikoo/OpenInv/releases";
|
||||
|
||||
@@ -66,6 +66,9 @@ permissions:
|
||||
openinv.access.level.2: false
|
||||
openinv.access.level.3: false
|
||||
openinv.access.level.4: false
|
||||
openinv.access.equal.edit: false
|
||||
openinv.access.equal.view: false
|
||||
openinv.access.equal.deny: false
|
||||
# Spectate features
|
||||
openinv.spectate:
|
||||
children:
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
"pack": {
|
||||
"description": "Improve OpenInv's legibility",
|
||||
"min_format": 34,
|
||||
"max_format": [69, 0],
|
||||
"max_format": [75, 0],
|
||||
"pack_format": 64,
|
||||
"supported_formats": [ 34, 69 ]
|
||||
"supported_formats": [ 34, 75 ]
|
||||
},
|
||||
"overlays": {
|
||||
"entries": [
|
||||
{
|
||||
"min_format": 44,
|
||||
"max_format": [69, 0],
|
||||
"formats": [ 44, 69 ],
|
||||
"max_format": [75, 0],
|
||||
"formats": [ 44, 75 ],
|
||||
"directory": "openinv_44"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -19,6 +19,7 @@ if (!java.lang.Boolean.getBoolean("jitpack")) {
|
||||
|
||||
val internals = listOf(
|
||||
"common",
|
||||
"paper1_21_10",
|
||||
"paper1_21_8",
|
||||
"paper1_21_5",
|
||||
"paper1_21_4",
|
||||
|
||||
Reference in new issue
Block a user