Compare commits

...

21 Commits
4.1.1 ... 4.1.5

Author SHA1 Message Date
Jikoo
9705cb156b Bump version to 4.1.6-SNAPSHOT for development 2020-11-03 18:32:43 -05:00
Jikoo
1c45ef517f Bump version to 4.1.5 for release 2020-11-03 18:32:11 -05:00
Jikoo
3fee84fc58 Add support for 1.16.4, drop 1.16.1 2020-11-03 18:19:34 -05:00
Jikoo
00113cc4d4 These are my favorite version bumps 2020-09-15 13:47:12 -04:00
Jikoo
788f022e74 Mitigate some permissions confusion
For some reason, certain permissions plugins seem to not respect our declared default false nodes. To alleviate user confusion, these nodes will not be allowed to be used via wildcard internally.
2020-09-15 13:44:50 -04:00
Jikoo
da55790fd2 Allow spectators to edit inventories
Requires permission OpenInv.spectate
Closes #155
2020-09-15 13:35:04 -04:00
Jikoo
1a6d513603 Reduce technical debt
* Reduce duplicate code
* Use more specific functional interfaces where available
* Fix some potential NPEs
* Remove some unnecessary/nonfunctional code
* Merge inventory listeners - no longer need to keep separate due to event availability
* Removed TODO items that probably won't ever be implemented. Good ideas, too drastic changes or too much work to maintain.
2020-09-15 12:51:49 -04:00
Jikoo
a5b02ab26a Bump version to 4.1.5-SNAPSHOT for development 2020-08-22 12:22:00 -04:00
Jikoo
0c3ce2dfb3 Bump version to 4.1.4 for release 2020-08-22 12:21:22 -04:00
Jikoo
a1f4649a09 Reword invalid version message, include releases link 2020-08-22 12:00:08 -04:00
Jikoo
100d0e12cd Update to 1.16.2 2020-08-12 00:06:20 -04:00
Jikoo
3e629798e5 Bump version to 4.1.4-SNAPSHOT for development 2020-07-15 23:23:31 -04:00
Jikoo
7c1f15974c Bump version to 4.1.3 for release 2020-07-15 23:23:03 -04:00
mfnalex
d992237766 Add support for 3rd party plugins firing PlayerInteractEvent (#146)
* Add support for InvUnload

* generalize 3rd party plugins' event check
2020-07-15 22:38:38 -04:00
Jikoo
c93464e643 Fix double chest loot generation with AnyContainer (#142) 2020-07-08 20:44:15 -04:00
Jikoo
56afefc82b Bump version to 4.1.3-SNAPSHOT for development 2020-06-25 19:40:07 -04:00
Jikoo
f0a66570d2 Bump version to 4.1.2 for release 2020-06-25 19:39:38 -04:00
Jikoo
201a3578bf Add 1.16 support, drop 1.14 (#141) 2020-06-25 19:38:38 -04:00
Nathaniel Freeman
1228fc2de2 es_ES translation 2020-06-24 07:12:20 -04:00
NotMyFault
2561e75ae5 Fix typo 2020-06-02 19:01:33 -04:00
N0tMyFaultOG
80661b9465 Add german translation 2020-06-02 17:59:31 -04:00
36 changed files with 2186 additions and 526 deletions

View File

@@ -136,6 +136,10 @@ OpenInv is a [Bukkit plugin](https://dev.bukkit.org/bukkit-plugins/openinv/) whi
<td>OpenInv.silent.default</td> <td>OpenInv.silent.default</td>
<td>Cause SilentContainer to be enabled by default.</td> <td>Cause SilentContainer to be enabled by default.</td>
</tr> </tr>
<tr>
<td>OpenInv.spectate</td>
<td>Allows users in spectate gamemode to edit inventories.</td>
</tr>
</table> </table>
## For Developers ## For Developers
@@ -152,7 +156,7 @@ The final file is `target/OpenInv.jar`
## License ## License
``` ```
Copyright (C) 2011-2019 lishid. All rights reserved. Copyright (C) 2011-2020 lishid. All rights reserved.
This program is free software: you can redistribute it and/or modify This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by

View File

@@ -21,7 +21,7 @@
<parent> <parent>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvparent</artifactId> <artifactId>openinvparent</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</parent> </parent>
<artifactId>openinvapi</artifactId> <artifactId>openinvapi</artifactId>

View File

@@ -18,6 +18,7 @@ package com.lishid.openinv.util;
import com.lishid.openinv.internal.IInventoryAccess; import com.lishid.openinv.internal.IInventoryAccess;
import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
@@ -33,9 +34,8 @@ public class InventoryAccess implements IInventoryAccess {
static { static {
String packageName = Bukkit.getServer().getClass().getPackage().getName(); String packageName = Bukkit.getServer().getClass().getPackage().getName();
String version = packageName.substring(packageName.lastIndexOf('.') + 1);
try { try {
craftInventory = Class.forName("org.bukkit.craftbukkit." + version + ".inventory.CraftInventory"); craftInventory = Class.forName(packageName + ".inventory.CraftInventory");
} catch (ClassNotFoundException ignored) {} } catch (ClassNotFoundException ignored) {}
try { try {
getInventory = craftInventory.getDeclaredMethod("getInventory"); getInventory = craftInventory.getDeclaredMethod("getInventory");
@@ -47,62 +47,42 @@ public class InventoryAccess implements IInventoryAccess {
} }
public static boolean isPlayerInventory(@NotNull Inventory inventory) { public static boolean isPlayerInventory(@NotNull Inventory inventory) {
if (craftInventory.isAssignableFrom(inventory.getClass())) { return getPlayerInventory(inventory) != null;
try {
return getInventory.invoke(inventory) instanceof ISpecialPlayerInventory;
} catch (ReflectiveOperationException ignored) {}
}
return grabFieldOfTypeFromObject(ISpecialPlayerInventory.class, inventory) != null;
} }
public static ISpecialPlayerInventory getPlayerInventory(@NotNull Inventory inventory) { public static @Nullable ISpecialPlayerInventory getPlayerInventory(@NotNull Inventory inventory) {
Object inv = null; return getSpecialInventory(ISpecialPlayerInventory.class, inventory);
if (craftInventory.isAssignableFrom(inventory.getClass())) {
try {
inv = getInventory.invoke(inventory);
} catch (ReflectiveOperationException ignored) {}
}
if (inv == null) {
inv = grabFieldOfTypeFromObject(ISpecialPlayerInventory.class, inventory);
}
if (inv instanceof ISpecialPlayerInventory) {
return (ISpecialPlayerInventory) inv;
}
return null;
} }
public static boolean isEnderChest(@NotNull Inventory inventory) { public static boolean isEnderChest(@NotNull Inventory inventory) {
if (craftInventory.isAssignableFrom(inventory.getClass())) { return getEnderChest(inventory) != null;
try {
return getInventory.invoke(inventory) instanceof ISpecialEnderChest;
} catch (ReflectiveOperationException ignored) {}
}
return grabFieldOfTypeFromObject(ISpecialEnderChest.class, inventory) != null;
} }
public static ISpecialEnderChest getEnderChest(@NotNull Inventory inventory) { public static @Nullable ISpecialEnderChest getEnderChest(@NotNull Inventory inventory) {
Object inv = null; return getSpecialInventory(ISpecialEnderChest.class, inventory);
if (craftInventory.isAssignableFrom(inventory.getClass())) { }
private static <T extends ISpecialInventory> @Nullable T getSpecialInventory(@NotNull Class<T> expected, @NotNull Inventory inventory) {
Object inv;
if (craftInventory != null && getInventory != null && craftInventory.isAssignableFrom(inventory.getClass())) {
try { try {
inv = getInventory.invoke(inventory); inv = getInventory.invoke(inventory);
if (expected.isInstance(inv)) {
return expected.cast(inv);
}
} catch (ReflectiveOperationException ignored) {} } catch (ReflectiveOperationException ignored) {}
} }
if (inv == null) { inv = grabFieldOfTypeFromObject(ISpecialPlayerInventory.class, inventory);
inv = grabFieldOfTypeFromObject(ISpecialEnderChest.class, inventory);
}
if (inv instanceof ISpecialEnderChest) { if (expected.isInstance(inv)) {
return (ISpecialEnderChest) inv; return expected.cast(inv);
} }
return null; return null;
} }
private static <T> T grabFieldOfTypeFromObject(final Class<T> type, final Object object) { private static <T> @Nullable T grabFieldOfTypeFromObject(final Class<T> type, final Object object) {
// Use reflection to find the IInventory // Use reflection to find the IInventory
Class<?> clazz = object.getClass(); Class<?> clazz = object.getClass();
T result = null; T result = null;
@@ -142,4 +122,5 @@ public class InventoryAccess implements IInventoryAccess {
public boolean isSpecialPlayerInventory(@NotNull Inventory inventory) { public boolean isSpecialPlayerInventory(@NotNull Inventory inventory) {
return isPlayerInventory(inventory); return isPlayerInventory(inventory);
} }
} }

View File

@@ -21,7 +21,7 @@
<parent> <parent>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvparent</artifactId> <artifactId>openinvparent</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</parent> </parent>
<artifactId>openinvassembly</artifactId> <artifactId>openinvassembly</artifactId>

View File

@@ -20,7 +20,7 @@
<parent> <parent>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvparent</artifactId> <artifactId>openinvparent</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</parent> </parent>
<artifactId>openinvinternal</artifactId> <artifactId>openinvinternal</artifactId>
@@ -34,8 +34,9 @@
<id>all</id> <id>all</id>
<modules> <modules>
<module>v1_8_R3</module> <module>v1_8_R3</module>
<module>v1_14_R1</module>
<module>v1_15_R1</module> <module>v1_15_R1</module>
<module>v1_16_R2</module>
<module>v1_16_R3</module>
</modules> </modules>
</profile> </profile>

View File

@@ -22,7 +22,7 @@
<parent> <parent>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvinternal</artifactId> <artifactId>openinvinternal</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</parent> </parent>
<artifactId>openinvadapter1_15_R1</artifactId> <artifactId>openinvadapter1_15_R1</artifactId>
@@ -38,7 +38,7 @@
<dependency> <dependency>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvplugincore</artifactId> <artifactId>openinvplugincore</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -33,7 +33,6 @@ import net.minecraft.server.v1_15_R1.ContainerChest;
import net.minecraft.server.v1_15_R1.Containers; import net.minecraft.server.v1_15_R1.Containers;
import net.minecraft.server.v1_15_R1.EntityHuman; import net.minecraft.server.v1_15_R1.EntityHuman;
import net.minecraft.server.v1_15_R1.EntityPlayer; import net.minecraft.server.v1_15_R1.EntityPlayer;
import net.minecraft.server.v1_15_R1.EnumChatFormat;
import net.minecraft.server.v1_15_R1.EnumGamemode; import net.minecraft.server.v1_15_R1.EnumGamemode;
import net.minecraft.server.v1_15_R1.IBlockData; import net.minecraft.server.v1_15_R1.IBlockData;
import net.minecraft.server.v1_15_R1.IChatBaseComponent; import net.minecraft.server.v1_15_R1.IChatBaseComponent;
@@ -192,7 +191,7 @@ public class AnySilentContainer implements IAnySilentContainer {
InventoryEnderChest enderChest = player.getEnderChest(); InventoryEnderChest enderChest = player.getEnderChest();
enderChest.a((TileEntityEnderChest) tile); enderChest.a((TileEntityEnderChest) tile);
player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> { player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> {
Containers containers; Containers<?> containers;
int rows = enderChest.getSize() / 9; int rows = enderChest.getSize() / 9;
switch (rows) { switch (rows) {
case 1: case 1:
@@ -251,8 +250,8 @@ public class AnySilentContainer implements IAnySilentContainer {
TileEntityChest rightChest = chestType == BlockPropertyChestType.RIGHT ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile; TileEntityChest rightChest = chestType == BlockPropertyChestType.RIGHT ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile;
TileEntityChest leftChest = chestType == BlockPropertyChestType.RIGHT ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory); TileEntityChest leftChest = chestType == BlockPropertyChestType.RIGHT ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory);
if (rightChest.lootTable != null || leftChest.lootTable != null) { if (silentchest && (rightChest.lootTable != null || leftChest.lootTable != null)) {
player.a(new ChatMessage("Loot not generated! Please disable /silentcontainer.").a(EnumChatFormat.RED), true); OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false; return false;
} }

View File

@@ -22,23 +22,23 @@
<parent> <parent>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvinternal</artifactId> <artifactId>openinvinternal</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</parent> </parent>
<artifactId>openinvadapter1_14_R1</artifactId> <artifactId>openinvadapter1_16_R2</artifactId>
<name>OpenInvAdapter1_14_R1</name> <name>OpenInvAdapter1_16_R2</name>
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId> <artifactId>spigot</artifactId>
<version>1.14.3-R0.1-SNAPSHOT</version> <version>1.16.3-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvplugincore</artifactId> <artifactId>openinvplugincore</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -14,40 +14,38 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.lishid.openinv.internal.v1_14_R1; package com.lishid.openinv.internal.v1_16_R2;
import com.lishid.openinv.OpenInv; import com.lishid.openinv.OpenInv;
import com.lishid.openinv.internal.IAnySilentContainer; import com.lishid.openinv.internal.IAnySilentContainer;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import net.minecraft.server.v1_14_R1.Block; import net.minecraft.server.v1_16_R2.Block;
import net.minecraft.server.v1_14_R1.BlockBarrel; import net.minecraft.server.v1_16_R2.BlockBarrel;
import net.minecraft.server.v1_14_R1.BlockChest; import net.minecraft.server.v1_16_R2.BlockChest;
import net.minecraft.server.v1_14_R1.BlockChestTrapped; import net.minecraft.server.v1_16_R2.BlockChestTrapped;
import net.minecraft.server.v1_14_R1.BlockEnderChest; import net.minecraft.server.v1_16_R2.BlockPosition;
import net.minecraft.server.v1_14_R1.BlockPosition; import net.minecraft.server.v1_16_R2.BlockPropertyChestType;
import net.minecraft.server.v1_14_R1.BlockPropertyChestType; import net.minecraft.server.v1_16_R2.BlockShulkerBox;
import net.minecraft.server.v1_14_R1.BlockShulkerBox; import net.minecraft.server.v1_16_R2.ChatMessage;
import net.minecraft.server.v1_14_R1.ChatMessage; import net.minecraft.server.v1_16_R2.Container;
import net.minecraft.server.v1_14_R1.Container; import net.minecraft.server.v1_16_R2.ContainerChest;
import net.minecraft.server.v1_14_R1.ContainerChest; import net.minecraft.server.v1_16_R2.Containers;
import net.minecraft.server.v1_14_R1.Containers; import net.minecraft.server.v1_16_R2.EntityHuman;
import net.minecraft.server.v1_14_R1.EntityHuman; import net.minecraft.server.v1_16_R2.EntityPlayer;
import net.minecraft.server.v1_14_R1.EntityPlayer; import net.minecraft.server.v1_16_R2.EnumGamemode;
import net.minecraft.server.v1_14_R1.EnumChatFormat; import net.minecraft.server.v1_16_R2.IBlockData;
import net.minecraft.server.v1_14_R1.EnumGamemode; import net.minecraft.server.v1_16_R2.IChatBaseComponent;
import net.minecraft.server.v1_14_R1.IBlockData; import net.minecraft.server.v1_16_R2.ITileInventory;
import net.minecraft.server.v1_14_R1.IChatBaseComponent; import net.minecraft.server.v1_16_R2.InventoryEnderChest;
import net.minecraft.server.v1_14_R1.ITileInventory; import net.minecraft.server.v1_16_R2.InventoryLargeChest;
import net.minecraft.server.v1_14_R1.InventoryEnderChest; import net.minecraft.server.v1_16_R2.PlayerInteractManager;
import net.minecraft.server.v1_14_R1.InventoryLargeChest; import net.minecraft.server.v1_16_R2.PlayerInventory;
import net.minecraft.server.v1_14_R1.PlayerInteractManager; import net.minecraft.server.v1_16_R2.TileEntity;
import net.minecraft.server.v1_14_R1.PlayerInventory; import net.minecraft.server.v1_16_R2.TileEntityChest;
import net.minecraft.server.v1_14_R1.TileEntity; import net.minecraft.server.v1_16_R2.TileEntityEnderChest;
import net.minecraft.server.v1_14_R1.TileEntityChest; import net.minecraft.server.v1_16_R2.TileEntityLootable;
import net.minecraft.server.v1_14_R1.TileEntityEnderChest; import net.minecraft.server.v1_16_R2.TileInventory;
import net.minecraft.server.v1_14_R1.TileEntityLootable; import net.minecraft.server.v1_16_R2.World;
import net.minecraft.server.v1_14_R1.TileInventory;
import net.minecraft.server.v1_14_R1.World;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Statistic; import org.bukkit.Statistic;
import org.bukkit.block.Barrel; import org.bukkit.block.Barrel;
@@ -216,7 +214,7 @@ public class AnySilentContainer implements IAnySilentContainer {
break; break;
} }
return new ContainerChest(containers, containerCounter, playerInventory, enderChest, rows); return new ContainerChest(containers, containerCounter, playerInventory, enderChest, rows);
}, BlockEnderChest.d)); }, new ChatMessage("container.enderchest")));
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED); bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true; return true;
} }
@@ -231,16 +229,16 @@ public class AnySilentContainer implements IAnySilentContainer {
if (block instanceof BlockChest) { if (block instanceof BlockChest) {
BlockPropertyChestType chestType = blockData.get(BlockChest.b); BlockPropertyChestType chestType = blockData.get(BlockChest.c);
if (chestType != BlockPropertyChestType.SINGLE) { if (chestType != BlockPropertyChestType.SINGLE) {
BlockPosition adjacentBlockPosition = blockPosition.shift(BlockChest.j(blockData)); BlockPosition adjacentBlockPosition = blockPosition.shift(BlockChest.h(blockData));
IBlockData adjacentBlockData = world.getType(adjacentBlockPosition); IBlockData adjacentBlockData = world.getType(adjacentBlockPosition);
if (adjacentBlockData.getBlock() == block) { if (adjacentBlockData.getBlock() == block) {
BlockPropertyChestType adjacentChestType = adjacentBlockData.get(BlockChest.b); BlockPropertyChestType adjacentChestType = adjacentBlockData.get(BlockChest.c);
if (adjacentChestType != BlockPropertyChestType.SINGLE && chestType != adjacentChestType if (adjacentChestType != BlockPropertyChestType.SINGLE && chestType != adjacentChestType
&& adjacentBlockData.get(BlockChest.FACING) == blockData.get(BlockChest.FACING)) { && adjacentBlockData.get(BlockChest.FACING) == blockData.get(BlockChest.FACING)) {
@@ -251,8 +249,8 @@ public class AnySilentContainer implements IAnySilentContainer {
TileEntityChest rightChest = chestType == BlockPropertyChestType.RIGHT ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile; TileEntityChest rightChest = chestType == BlockPropertyChestType.RIGHT ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile;
TileEntityChest leftChest = chestType == BlockPropertyChestType.RIGHT ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory); TileEntityChest leftChest = chestType == BlockPropertyChestType.RIGHT ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory);
if (rightChest.lootTable != null || leftChest.lootTable != null) { if (silentchest && (rightChest.lootTable != null || leftChest.lootTable != null)) {
player.a(new ChatMessage("Loot not generated! Please disable /silentcontainer.").a(EnumChatFormat.RED), true); OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false; return false;
} }

View File

@@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.lishid.openinv.internal.v1_14_R1; package com.lishid.openinv.internal.v1_16_R2;
import com.lishid.openinv.OpenInv; import com.lishid.openinv.OpenInv;
import com.lishid.openinv.internal.IPlayerDataManager; import com.lishid.openinv.internal.IPlayerDataManager;
@@ -23,30 +23,32 @@ import com.mojang.authlib.GameProfile;
import java.io.File; import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import net.minecraft.server.v1_14_R1.ChatComponentText; import net.minecraft.server.v1_16_R2.ChatComponentText;
import net.minecraft.server.v1_14_R1.ChatMessageType; import net.minecraft.server.v1_16_R2.ChatMessageType;
import net.minecraft.server.v1_14_R1.Container; import net.minecraft.server.v1_16_R2.Container;
import net.minecraft.server.v1_14_R1.Containers; import net.minecraft.server.v1_16_R2.Containers;
import net.minecraft.server.v1_14_R1.DimensionManager; import net.minecraft.server.v1_16_R2.Entity;
import net.minecraft.server.v1_14_R1.Entity; import net.minecraft.server.v1_16_R2.EntityHuman;
import net.minecraft.server.v1_14_R1.EntityHuman; import net.minecraft.server.v1_16_R2.EntityPlayer;
import net.minecraft.server.v1_14_R1.EntityPlayer; import net.minecraft.server.v1_16_R2.MinecraftServer;
import net.minecraft.server.v1_14_R1.MinecraftServer; import net.minecraft.server.v1_16_R2.NBTCompressedStreamTools;
import net.minecraft.server.v1_14_R1.NBTCompressedStreamTools; import net.minecraft.server.v1_16_R2.NBTTagCompound;
import net.minecraft.server.v1_14_R1.NBTTagCompound; import net.minecraft.server.v1_16_R2.PacketPlayOutChat;
import net.minecraft.server.v1_14_R1.PacketPlayOutChat; import net.minecraft.server.v1_16_R2.PacketPlayOutOpenWindow;
import net.minecraft.server.v1_14_R1.PacketPlayOutOpenWindow; import net.minecraft.server.v1_16_R2.PlayerInteractManager;
import net.minecraft.server.v1_14_R1.PlayerInteractManager; import net.minecraft.server.v1_16_R2.PlayerInventory;
import net.minecraft.server.v1_14_R1.PlayerInventory; import net.minecraft.server.v1_16_R2.SystemUtils;
import net.minecraft.server.v1_14_R1.WorldNBTStorage; import net.minecraft.server.v1_16_R2.World;
import net.minecraft.server.v1_16_R2.WorldNBTStorage;
import net.minecraft.server.v1_16_R2.WorldServer;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.Server; import org.bukkit.Server;
import org.bukkit.craftbukkit.v1_14_R1.CraftServer; import org.bukkit.craftbukkit.v1_16_R2.CraftServer;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory; import org.bukkit.craftbukkit.v1_16_R2.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftContainer; import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftContainer;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.inventory.InventoryType; import org.bukkit.event.inventory.InventoryType;
@@ -57,7 +59,7 @@ import org.jetbrains.annotations.Nullable;
public class PlayerDataManager implements IPlayerDataManager { public class PlayerDataManager implements IPlayerDataManager {
private Field bukkitEntity; private @Nullable Field bukkitEntity;
public PlayerDataManager() { public PlayerDataManager() {
try { try {
@@ -90,6 +92,7 @@ public class PlayerDataManager implements IPlayerDataManager {
return nmsPlayer; return nmsPlayer;
} }
@Nullable
@Override @Override
public Player loadPlayer(@NotNull final OfflinePlayer offline) { public Player loadPlayer(@NotNull final OfflinePlayer offline) {
// Ensure player has data // Ensure player has data
@@ -98,11 +101,17 @@ public class PlayerDataManager implements IPlayerDataManager {
} }
// Create a profile and entity to load the player data // Create a profile and entity to load the player data
// See net.minecraft.server.PlayerList#attemptLogin
GameProfile profile = new GameProfile(offline.getUniqueId(), GameProfile profile = new GameProfile(offline.getUniqueId(),
offline.getName() != null ? offline.getName() : offline.getUniqueId().toString()); offline.getName() != null ? offline.getName() : offline.getUniqueId().toString());
MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer(); MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(DimensionManager.OVERWORLD), profile, WorldServer worldServer = server.getWorldServer(World.OVERWORLD);
new PlayerInteractManager(server.getWorldServer(DimensionManager.OVERWORLD)));
if (worldServer == null) {
return null;
}
EntityPlayer entity = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer));
try { try {
injectPlayer(entity); injectPlayer(entity);
@@ -133,7 +142,7 @@ public class PlayerDataManager implements IPlayerDataManager {
super.saveData(); super.saveData();
// See net.minecraft.server.WorldNBTStorage#save(EntityPlayer) // See net.minecraft.server.WorldNBTStorage#save(EntityPlayer)
try { try {
WorldNBTStorage worldNBTStorage = (WorldNBTStorage) player.server.getPlayerList().playerFileData; WorldNBTStorage worldNBTStorage = player.server.getPlayerList().playerFileData;
NBTTagCompound playerData = player.save(new NBTTagCompound()); NBTTagCompound playerData = player.save(new NBTTagCompound());
@@ -152,11 +161,10 @@ public class PlayerDataManager implements IPlayerDataManager {
NBTCompressedStreamTools.a(playerData, new FileOutputStream(file)); NBTCompressedStreamTools.a(playerData, new FileOutputStream(file));
if (file1.exists()) { if (file1.exists() && !file1.delete() || !file.renameTo(file1)) {
file1.delete(); LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString());
} }
file.renameTo(file1);
} catch (Exception e) { } catch (Exception e) {
LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString()); LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString());
} }
@@ -280,7 +288,7 @@ public class PlayerDataManager implements IPlayerDataManager {
// For action bar chat, color codes are still supported but JSON text color is not allowed. Do not convert text. // For action bar chat, color codes are still supported but JSON text color is not allowed. Do not convert text.
if (nmsPlayer.playerConnection != null) { if (nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(new PacketPlayOutChat(new ChatComponentText(message), ChatMessageType.GAME_INFO)); nmsPlayer.playerConnection.sendPacket(new PacketPlayOutChat(new ChatComponentText(message), ChatMessageType.GAME_INFO, SystemUtils.b));
} }
} }

View File

@@ -14,25 +14,26 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.lishid.openinv.internal.v1_14_R1; package com.lishid.openinv.internal.v1_16_R2;
import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialEnderChest;
import java.util.List; import java.util.List;
import net.minecraft.server.v1_14_R1.AutoRecipeStackManager; import net.minecraft.server.v1_16_R2.AutoRecipeStackManager;
import net.minecraft.server.v1_14_R1.ContainerUtil; import net.minecraft.server.v1_16_R2.ContainerUtil;
import net.minecraft.server.v1_14_R1.EntityHuman; import net.minecraft.server.v1_16_R2.EntityHuman;
import net.minecraft.server.v1_14_R1.EntityPlayer; import net.minecraft.server.v1_16_R2.EntityPlayer;
import net.minecraft.server.v1_14_R1.IInventoryListener; import net.minecraft.server.v1_16_R2.IInventoryListener;
import net.minecraft.server.v1_14_R1.InventoryEnderChest; import net.minecraft.server.v1_16_R2.InventoryEnderChest;
import net.minecraft.server.v1_14_R1.ItemStack; import net.minecraft.server.v1_16_R2.ItemStack;
import net.minecraft.server.v1_14_R1.NonNullList; import net.minecraft.server.v1_16_R2.NonNullList;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftHumanEntity; import org.bukkit.craftbukkit.v1_16_R2.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventory; import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftInventory;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEnderChest { public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEnderChest {
@@ -115,7 +116,7 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn
} }
@Override @Override
public Location getLocation() { public @Nullable Location getLocation() {
return null; return null;
} }
@@ -131,7 +132,7 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn
@Override @Override
public ItemStack getItem(int i) { public ItemStack getItem(int i) {
return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.a; return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.b;
} }
@Override @Override
@@ -153,7 +154,7 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn
if (itemstack2.isEmpty()) { if (itemstack2.isEmpty()) {
this.setItem(i, itemstack1); this.setItem(i, itemstack1);
this.update(); this.update();
return ItemStack.a; return ItemStack.b;
} }
if (ItemStack.c(itemstack2, itemstack1)) { if (ItemStack.c(itemstack2, itemstack1)) {
@@ -164,7 +165,7 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn
itemstack1.subtract(k); itemstack1.subtract(k);
if (itemstack1.isEmpty()) { if (itemstack1.isEmpty()) {
this.update(); this.update();
return ItemStack.a; return ItemStack.b;
} }
} }
} }
@@ -181,9 +182,9 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn
public ItemStack splitWithoutUpdate(int i) { public ItemStack splitWithoutUpdate(int i) {
ItemStack itemstack = this.items.get(i); ItemStack itemstack = this.items.get(i);
if (itemstack.isEmpty()) { if (itemstack.isEmpty()) {
return ItemStack.a; return ItemStack.b;
} else { } else {
this.items.set(i, ItemStack.a); this.items.set(i, ItemStack.b);
return itemstack; return itemstack;
} }
} }
@@ -204,7 +205,7 @@ public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEn
} }
@Override @Override
public boolean isNotEmpty() { public boolean isEmpty() {
for (ItemStack itemstack : this.items) { for (ItemStack itemstack : this.items) {
if (!itemstack.isEmpty()) { if (!itemstack.isEmpty()) {

View File

@@ -14,7 +14,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>. * along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package com.lishid.openinv.internal.v1_14_R1; package com.lishid.openinv.internal.v1_16_R2;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory;
@@ -22,29 +22,31 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.function.Predicate; import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import net.minecraft.server.v1_14_R1.AutoRecipeStackManager; import net.minecraft.server.v1_16_R2.AutoRecipeStackManager;
import net.minecraft.server.v1_14_R1.ChatMessage; import net.minecraft.server.v1_16_R2.ChatMessage;
import net.minecraft.server.v1_14_R1.ContainerUtil; import net.minecraft.server.v1_16_R2.ContainerUtil;
import net.minecraft.server.v1_14_R1.CrashReport; import net.minecraft.server.v1_16_R2.CrashReport;
import net.minecraft.server.v1_14_R1.CrashReportSystemDetails; import net.minecraft.server.v1_16_R2.CrashReportSystemDetails;
import net.minecraft.server.v1_14_R1.EntityHuman; import net.minecraft.server.v1_16_R2.DamageSource;
import net.minecraft.server.v1_14_R1.EntityPlayer; import net.minecraft.server.v1_16_R2.EntityHuman;
import net.minecraft.server.v1_14_R1.EnumItemSlot; import net.minecraft.server.v1_16_R2.EntityPlayer;
import net.minecraft.server.v1_14_R1.IBlockData; import net.minecraft.server.v1_16_R2.EnumItemSlot;
import net.minecraft.server.v1_14_R1.IChatBaseComponent; import net.minecraft.server.v1_16_R2.IBlockData;
import net.minecraft.server.v1_14_R1.Item; import net.minecraft.server.v1_16_R2.IChatBaseComponent;
import net.minecraft.server.v1_14_R1.ItemArmor; import net.minecraft.server.v1_16_R2.IInventory;
import net.minecraft.server.v1_14_R1.ItemStack; import net.minecraft.server.v1_16_R2.Item;
import net.minecraft.server.v1_14_R1.NBTTagCompound; import net.minecraft.server.v1_16_R2.ItemArmor;
import net.minecraft.server.v1_14_R1.NBTTagList; import net.minecraft.server.v1_16_R2.ItemStack;
import net.minecraft.server.v1_14_R1.NonNullList; import net.minecraft.server.v1_16_R2.NBTTagCompound;
import net.minecraft.server.v1_14_R1.PacketPlayOutSetSlot; import net.minecraft.server.v1_16_R2.NBTTagList;
import net.minecraft.server.v1_14_R1.PlayerInventory; import net.minecraft.server.v1_16_R2.NonNullList;
import net.minecraft.server.v1_14_R1.ReportedException; import net.minecraft.server.v1_16_R2.PacketPlayOutSetSlot;
import net.minecraft.server.v1_14_R1.World; import net.minecraft.server.v1_16_R2.PlayerInventory;
import net.minecraft.server.v1_16_R2.ReportedException;
import net.minecraft.server.v1_16_R2.World;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftHumanEntity; import org.bukkit.craftbukkit.v1_16_R2.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventory; import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftInventory;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
@@ -117,7 +119,7 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
} }
if (i >= list.size()) { if (i >= list.size()) {
return ItemStack.a; return ItemStack.b;
} }
return list.get(i); return list.get(i);
@@ -133,7 +135,7 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
i -= next.size(); i -= next.size();
} }
return list == null ? ItemStack.a : list.get(i); return list == null ? ItemStack.b : list.get(i);
} }
@Override @Override
@@ -229,10 +231,10 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
} }
if (i >= list.size()) { if (i >= list.size()) {
return ItemStack.a; return ItemStack.b;
} }
return list.get(i).isEmpty() ? ItemStack.a : ContainerUtil.a(list, i, j); return list.get(i).isEmpty() ? ItemStack.b : ContainerUtil.a(list, i, j);
} }
@Override @Override
@@ -254,17 +256,17 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
} }
if (i >= list.size()) { if (i >= list.size()) {
return ItemStack.a; return ItemStack.b;
} }
if (!list.get(i).isEmpty()) { if (!list.get(i).isEmpty()) {
ItemStack itemstack = list.get(i); ItemStack itemstack = list.get(i);
list.set(i, ItemStack.a); list.set(i, ItemStack.b);
return itemstack; return itemstack;
} }
return ItemStack.a; return ItemStack.b;
} }
@Override @Override
@@ -304,10 +306,10 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
@Override @Override
public ItemStack getItemInHand() { public ItemStack getItemInHand() {
return d(this.itemInHandIndex) ? this.items.get(this.itemInHandIndex) : ItemStack.a; return d(this.itemInHandIndex) ? this.items.get(this.itemInHandIndex) : ItemStack.b;
} }
private boolean a(ItemStack itemstack, ItemStack itemstack1) { private boolean isSimilarAndNotFull(ItemStack itemstack, ItemStack itemstack1) {
return !itemstack.isEmpty() && this.b(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize(); return !itemstack.isEmpty() && this.b(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize();
} }
@@ -325,8 +327,8 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
return itemstack.getCount(); return itemstack.getCount();
} }
if (!this.a(itemstack, itemstack1)) { if (!this.isSimilarAndNotFull(itemstack, itemstack1)) {
remains -= (itemstack1.getMaxStackSize() < this.getMaxStackSize() ? itemstack1.getMaxStackSize() : this.getMaxStackSize()) - itemstack1.getCount(); remains -= Math.min(itemstack1.getMaxStackSize(), this.getMaxStackSize()) - itemstack1.getCount();
} }
if (remains <= 0) { if (remains <= 0) {
@@ -334,6 +336,11 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
} }
} }
ItemStack offhandItemStack = this.getItem(this.items.size() + this.armor.size());
if (this.isSimilarAndNotFull(offhandItemStack, itemstack)) {
remains -= Math.min(offhandItemStack.getMaxStackSize(), this.getMaxStackSize()) - offhandItemStack.getCount();
}
return itemstack.getCount() - remains; return itemstack.getCount() - remains;
} }
@@ -390,41 +397,14 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
} }
@Override @Override
public int a(Predicate<ItemStack> predicate, int i) { public int a(Predicate<ItemStack> predicate, int i, IInventory iinventory) {
int j = 0; byte b0 = 0;
boolean flag = i == 0;
int k; int j = b0 + ContainerUtil.a(this, predicate, i - b0, flag);
for (k = 0; k < this.getSize(); ++k) { j += ContainerUtil.a(iinventory, predicate, i - j, flag);
ItemStack itemstack = this.getItem(k); j += ContainerUtil.a(this.getCarried(), predicate, i - j, flag);
if (!itemstack.isEmpty() && predicate.test(itemstack)) { if (this.getCarried().isEmpty()) {
int l = i <= 0 ? itemstack.getCount() : Math.min(i - j, itemstack.getCount()); this.setCarried(ItemStack.b);
j += l;
if (i != 0) {
itemstack.subtract(l);
if (itemstack.isEmpty()) {
this.setItem(k, ItemStack.a);
}
if (i > 0 && j >= i) {
return j;
}
}
}
}
if (!this.getCarried().isEmpty() && predicate.test(this.getCarried())) {
k = i <= 0 ? this.getCarried().getCount() : Math.min(i - j, this.getCarried().getCount());
j += k;
if (i != 0) {
this.getCarried().subtract(k);
if (this.getCarried().isEmpty()) {
this.setCarried(ItemStack.a);
}
if (i > 0 && j >= i) {
return j;
}
}
} }
return j; return j;
@@ -445,8 +425,9 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
ItemStack itemstack1 = this.getItem(i); ItemStack itemstack1 = this.getItem(i);
if (itemstack1.isEmpty()) { if (itemstack1.isEmpty()) {
itemstack1 = new ItemStack(item, 0); itemstack1 = new ItemStack(item, 0);
if (itemstack.hasTag()) { NBTTagCompound tag = itemstack.getTag();
itemstack1.setTag(itemstack.getTag().clone()); if (tag != null) {
itemstack1.setTag(tag.clone());
} }
this.setItem(i, itemstack1); this.setItem(i, itemstack1);
@@ -461,25 +442,23 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
k = this.getMaxStackSize() - itemstack1.getCount(); k = this.getMaxStackSize() - itemstack1.getCount();
} }
if (k == 0) { if (k != 0) {
return j;
} else {
j -= k; j -= k;
itemstack1.add(k); itemstack1.add(k);
itemstack1.d(5); itemstack1.d(5);
return j;
} }
return j;
} }
@Override @Override
public int firstPartial(ItemStack itemstack) { public int firstPartial(ItemStack itemstack) {
if (this.a(this.getItem(this.itemInHandIndex), itemstack)) { if (this.isSimilarAndNotFull(this.getItem(this.itemInHandIndex), itemstack)) {
return this.itemInHandIndex; return this.itemInHandIndex;
} else if (this.a(this.getItem(40), itemstack)) { } else if (this.isSimilarAndNotFull(this.getItem(40), itemstack)) {
return 40; return 40;
} else { } else {
for (int i = 0; i < this.items.size(); ++i) { for (int i = 0; i < this.items.size(); ++i) {
if (this.a(this.items.get(i), itemstack)) { if (this.isSimilarAndNotFull(this.items.get(i), itemstack)) {
return i; return i;
} }
} }
@@ -586,7 +565,7 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
for (List<ItemStack> list : this.f) { for (List<ItemStack> list : this.f) {
for (int i = 0; i < list.size(); ++i) { for (int i = 0; i < list.size(); ++i) {
if (list.get(i) == itemstack) { if (list.get(i) == itemstack) {
list.set(i, ItemStack.a); list.set(i, ItemStack.b);
break; break;
} }
} }
@@ -656,12 +635,12 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
} }
@Override @Override
public boolean isNotEmpty() { public boolean isEmpty() {
Iterator iterator = this.items.iterator(); Iterator<ItemStack> iterator = this.items.iterator();
ItemStack itemstack; ItemStack itemstack;
while (iterator.hasNext()) { while (iterator.hasNext()) {
itemstack = (ItemStack)iterator.next(); itemstack = iterator.next();
if (!itemstack.isEmpty()) { if (!itemstack.isEmpty()) {
return false; return false;
} }
@@ -670,7 +649,7 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
iterator = this.armor.iterator(); iterator = this.armor.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
itemstack = (ItemStack)iterator.next(); itemstack = iterator.next();
if (!itemstack.isEmpty()) { if (!itemstack.isEmpty()) {
return false; return false;
} }
@@ -679,7 +658,7 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
iterator = this.extraSlots.iterator(); iterator = this.extraSlots.iterator();
while (iterator.hasNext()) { while (iterator.hasNext()) {
itemstack = (ItemStack)iterator.next(); itemstack = iterator.next();
if (!itemstack.isEmpty()) { if (!itemstack.isEmpty()) {
return false; return false;
} }
@@ -695,12 +674,7 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
} }
@Override @Override
public boolean b(IBlockData iblockdata) { public void a(DamageSource damagesource, float f) {
return this.getItem(this.itemInHandIndex).b(iblockdata);
}
@Override
public void a(float f) {
if (f > 0.0F) { if (f > 0.0F) {
f /= 4.0F; f /= 4.0F;
if (f < 1.0F) { if (f < 1.0F) {
@@ -710,8 +684,8 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
for (int i = 0; i < this.armor.size(); ++i) { for (int i = 0; i < this.armor.size(); ++i) {
ItemStack itemstack = this.armor.get(0); ItemStack itemstack = this.armor.get(0);
int index = i; int index = i;
if (itemstack.getItem() instanceof ItemArmor) { if ((!damagesource.isFire() || !itemstack.getItem().u()) && itemstack.getItem() instanceof ItemArmor) {
itemstack.damage((int) f, this.player, (entityhuman) -> entityhuman.c(EnumItemSlot.a(EnumItemSlot.Function.ARMOR, index))); itemstack.damage((int) f, this.player, (entityHuman) -> entityHuman.broadcastItemBreak(EnumItemSlot.a(EnumItemSlot.Function.ARMOR, index)));
} }
} }
} }
@@ -723,7 +697,7 @@ public class SpecialPlayerInventory extends PlayerInventory implements ISpecialP
for (int i = 0; i < itemStacks.size(); ++i) { for (int i = 0; i < itemStacks.size(); ++i) {
ItemStack itemstack = itemStacks.get(i); ItemStack itemstack = itemStacks.get(i);
if (!itemstack.isEmpty()) { if (!itemstack.isEmpty()) {
itemStacks.set(i, ItemStack.a); itemStacks.set(i, ItemStack.b);
this.player.a(itemstack, true, false); this.player.a(itemstack, true, false);
} }
} }

75
internal/v1_16_R3/pom.xml Normal file
View File

@@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright (C) 2011-2020 lishid. All rights reserved.
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, version 3.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.lishid</groupId>
<artifactId>openinvinternal</artifactId>
<version>4.1.6-SNAPSHOT</version>
</parent>
<artifactId>openinvadapter1_16_R3</artifactId>
<name>OpenInvAdapter1_16_R3</name>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.16.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.lishid</groupId>
<artifactId>openinvplugincore</artifactId>
<version>4.1.6-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<minimizeJar>true</minimizeJar>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,358 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_16_R3;
import com.lishid.openinv.OpenInv;
import com.lishid.openinv.internal.IAnySilentContainer;
import java.lang.reflect.Field;
import net.minecraft.server.v1_16_R3.Block;
import net.minecraft.server.v1_16_R3.BlockBarrel;
import net.minecraft.server.v1_16_R3.BlockChest;
import net.minecraft.server.v1_16_R3.BlockChestTrapped;
import net.minecraft.server.v1_16_R3.BlockPosition;
import net.minecraft.server.v1_16_R3.BlockPropertyChestType;
import net.minecraft.server.v1_16_R3.BlockShulkerBox;
import net.minecraft.server.v1_16_R3.ChatMessage;
import net.minecraft.server.v1_16_R3.Container;
import net.minecraft.server.v1_16_R3.ContainerChest;
import net.minecraft.server.v1_16_R3.Containers;
import net.minecraft.server.v1_16_R3.EntityHuman;
import net.minecraft.server.v1_16_R3.EntityPlayer;
import net.minecraft.server.v1_16_R3.EnumGamemode;
import net.minecraft.server.v1_16_R3.IBlockData;
import net.minecraft.server.v1_16_R3.IChatBaseComponent;
import net.minecraft.server.v1_16_R3.ITileInventory;
import net.minecraft.server.v1_16_R3.InventoryEnderChest;
import net.minecraft.server.v1_16_R3.InventoryLargeChest;
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
import net.minecraft.server.v1_16_R3.PlayerInventory;
import net.minecraft.server.v1_16_R3.TileEntity;
import net.minecraft.server.v1_16_R3.TileEntityChest;
import net.minecraft.server.v1_16_R3.TileEntityEnderChest;
import net.minecraft.server.v1_16_R3.TileEntityLootable;
import net.minecraft.server.v1_16_R3.TileInventory;
import net.minecraft.server.v1_16_R3.World;
import org.bukkit.Material;
import org.bukkit.Statistic;
import org.bukkit.block.Barrel;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.EnderChest;
import org.bukkit.block.ShulkerBox;
import org.bukkit.block.data.BlockData;
import org.bukkit.block.data.Directional;
import org.bukkit.block.data.type.Chest;
import org.bukkit.entity.Cat;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryView;
import org.bukkit.util.BoundingBox;
import org.jetbrains.annotations.NotNull;
public class AnySilentContainer implements IAnySilentContainer {
private Field playerInteractManagerGamemode;
public AnySilentContainer() {
try {
this.playerInteractManagerGamemode = PlayerInteractManager.class.getDeclaredField("gamemode");
this.playerInteractManagerGamemode.setAccessible(true);
} catch (NoSuchFieldException | SecurityException e) {
System.err.println("[OpenInv] Unable to directly write player gamemode! SilentChest will fail.");
e.printStackTrace();
}
}
@Override
public boolean isAnySilentContainer(@NotNull final org.bukkit.block.Block bukkitBlock) {
if (bukkitBlock.getType() == Material.ENDER_CHEST) {
return true;
}
BlockState state = bukkitBlock.getState();
return state instanceof org.bukkit.block.Chest
|| state instanceof org.bukkit.block.ShulkerBox
|| state instanceof org.bukkit.block.Barrel;
}
@Override
public boolean isAnyContainerNeeded(@NotNull final Player p, @NotNull final org.bukkit.block.Block block) {
BlockState blockState = block.getState();
// Barrels do not require AnyContainer.
if (blockState instanceof Barrel) {
return false;
}
// Enderchests require a non-occluding block on top to open.
if (blockState instanceof EnderChest) {
return block.getRelative(0, 1, 0).getType().isOccluding();
}
// Shulker boxes require 1/2 a block clear in the direction they open.
if (blockState instanceof ShulkerBox) {
BoundingBox boundingBox = block.getBoundingBox();
if (boundingBox.getVolume() > 1) {
// Shulker box is already open.
return false;
}
BlockData blockData = block.getBlockData();
if (!(blockData instanceof Directional)) {
// Shouldn't be possible. Just in case, demand AnyChest.
return true;
}
Directional directional = (Directional) blockData;
BlockFace face = directional.getFacing();
boundingBox.shift(face.getDirection());
// Return whether or not bounding boxes overlap.
return block.getRelative(face, 1).getBoundingBox().overlaps(boundingBox);
}
if (!(blockState instanceof org.bukkit.block.Chest)) {
return false;
}
if (isBlockedChest(block)) {
return true;
}
BlockData blockData = block.getBlockData();
if (!(blockData instanceof Chest) || ((Chest) blockData).getType() == Chest.Type.SINGLE) {
return false;
}
Chest chest = (Chest) blockData;
int ordinal = (chest.getFacing().ordinal() + 4 + (chest.getType() == Chest.Type.RIGHT ? -1 : 1)) % 4;
BlockFace relativeFace = BlockFace.values()[ordinal];
org.bukkit.block.Block relative = block.getRelative(relativeFace);
if (relative.getType() != block.getType()) {
return false;
}
BlockData relativeData = relative.getBlockData();
if (!(relativeData instanceof Chest)) {
return false;
}
Chest relativeChest = (Chest) relativeData;
if (relativeChest.getFacing() != chest.getFacing()
|| relativeChest.getType() != (chest.getType() == Chest.Type.RIGHT ? Chest.Type.LEFT : Chest.Type.RIGHT)) {
return false;
}
return isBlockedChest(relative);
}
private boolean isBlockedChest(org.bukkit.block.Block block) {
org.bukkit.block.Block relative = block.getRelative(0, 1, 0);
return relative.getType().isOccluding()
|| block.getWorld().getNearbyEntities(BoundingBox.of(relative), entity -> entity instanceof Cat).size() > 0;
}
@Override
public boolean activateContainer(@NotNull final Player bukkitPlayer, final boolean silentchest,
@NotNull final org.bukkit.block.Block bukkitBlock) {
// Silent ender chest is API-only
if (silentchest && bukkitBlock.getType() == Material.ENDER_CHEST) {
bukkitPlayer.openInventory(bukkitPlayer.getEnderChest());
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true;
}
EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer);
final World world = player.world;
final BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());
final TileEntity tile = world.getTileEntity(blockPosition);
if (tile == null) {
return false;
}
if (tile instanceof TileEntityEnderChest) {
// Anychest ender chest. See net.minecraft.server.BlockEnderChest
InventoryEnderChest enderChest = player.getEnderChest();
enderChest.a((TileEntityEnderChest) tile);
player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> {
Containers<?> containers;
int rows = enderChest.getSize() / 9;
switch (rows) {
case 1:
containers = Containers.GENERIC_9X1;
break;
case 2:
containers = Containers.GENERIC_9X2;
break;
case 3:
default:
containers = Containers.GENERIC_9X3;
break;
case 4:
containers = Containers.GENERIC_9X4;
break;
case 5:
containers = Containers.GENERIC_9X5;
break;
case 6:
containers = Containers.GENERIC_9X6;
break;
}
return new ContainerChest(containers, containerCounter, playerInventory, enderChest, rows);
}, new ChatMessage("container.enderchest")));
bukkitPlayer.incrementStatistic(Statistic.ENDERCHEST_OPENED);
return true;
}
if (!(tile instanceof ITileInventory)) {
return false;
}
ITileInventory tileInventory = (ITileInventory) tile;
IBlockData blockData = world.getType(blockPosition);
Block block = blockData.getBlock();
if (block instanceof BlockChest) {
BlockPropertyChestType chestType = blockData.get(BlockChest.c);
if (chestType != BlockPropertyChestType.SINGLE) {
BlockPosition adjacentBlockPosition = blockPosition.shift(BlockChest.h(blockData));
IBlockData adjacentBlockData = world.getType(adjacentBlockPosition);
if (adjacentBlockData.getBlock() == block) {
BlockPropertyChestType adjacentChestType = adjacentBlockData.get(BlockChest.c);
if (adjacentChestType != BlockPropertyChestType.SINGLE && chestType != adjacentChestType
&& adjacentBlockData.get(BlockChest.FACING) == blockData.get(BlockChest.FACING)) {
TileEntity adjacentTile = world.getTileEntity(adjacentBlockPosition);
if (adjacentTile instanceof TileEntityChest && tileInventory instanceof TileEntityChest) {
TileEntityChest rightChest = chestType == BlockPropertyChestType.RIGHT ? ((TileEntityChest) tileInventory) : (TileEntityChest) adjacentTile;
TileEntityChest leftChest = chestType == BlockPropertyChestType.RIGHT ? (TileEntityChest) adjacentTile : ((TileEntityChest) tileInventory);
if (silentchest && (rightChest.lootTable != null || leftChest.lootTable != null)) {
OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false;
}
tileInventory = new ITileInventory() {
public Container createMenu(int containerCounter, PlayerInventory playerInventory, EntityHuman entityHuman) {
leftChest.d(playerInventory.player);
rightChest.d(playerInventory.player);
return ContainerChest.b(containerCounter, playerInventory, new InventoryLargeChest(rightChest, leftChest));
}
public IChatBaseComponent getScoreboardDisplayName() {
return new ChatMessage("container.chestDouble");
}
};
}
}
}
}
if (block instanceof BlockChestTrapped) {
bukkitPlayer.incrementStatistic(Statistic.TRAPPED_CHEST_TRIGGERED);
} else {
bukkitPlayer.incrementStatistic(Statistic.CHEST_OPENED);
}
}
if (block instanceof BlockShulkerBox) {
bukkitPlayer.incrementStatistic(Statistic.SHULKER_BOX_OPENED);
}
if (block instanceof BlockBarrel) {
bukkitPlayer.incrementStatistic(Statistic.OPEN_BARREL);
}
// AnyChest only - SilentChest not active, container unsupported, or unnecessary.
if (!silentchest || player.playerInteractManager.getGameMode() == EnumGamemode.SPECTATOR) {
player.openContainer(tileInventory);
return true;
}
// SilentChest requires access to setting players' gamemode directly.
if (this.playerInteractManagerGamemode == null) {
return false;
}
if (tile instanceof TileEntityLootable) {
TileEntityLootable lootable = (TileEntityLootable) tile;
if (lootable.lootTable != null) {
OpenInv.getPlugin(OpenInv.class).sendSystemMessage(bukkitPlayer, "messages.error.lootNotGenerated");
return false;
}
}
EnumGamemode gamemode = player.playerInteractManager.getGameMode();
this.forceGameMode(player, EnumGamemode.SPECTATOR);
player.openContainer(tileInventory);
this.forceGameMode(player, gamemode);
return true;
}
@Override
public void deactivateContainer(@NotNull final Player bukkitPlayer) {
if (this.playerInteractManagerGamemode == null) {
return;
}
InventoryView view = bukkitPlayer.getOpenInventory();
switch (view.getType()) {
case CHEST:
case ENDER_CHEST:
case SHULKER_BOX:
case BARREL:
break;
default:
return;
}
EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer);
EnumGamemode gamemode = player.playerInteractManager.getGameMode();
this.forceGameMode(player, EnumGamemode.SPECTATOR);
player.activeContainer.b(player);
player.activeContainer.a(player, false);
player.activeContainer.transferTo(player.defaultContainer, player.getBukkitEntity());
player.activeContainer = player.defaultContainer;
this.forceGameMode(player, gamemode);
}
private void forceGameMode(final EntityPlayer player, final EnumGamemode gameMode) {
if (this.playerInteractManagerGamemode == null) {
// No need to warn repeatedly, error on startup and lack of function should be enough.
return;
}
try {
if (!this.playerInteractManagerGamemode.isAccessible()) {
// Just in case, ensure accessible.
this.playerInteractManagerGamemode.setAccessible(true);
}
this.playerInteractManagerGamemode.set(player.playerInteractManager, gameMode);
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,295 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_16_R3;
import com.lishid.openinv.OpenInv;
import com.lishid.openinv.internal.IPlayerDataManager;
import com.lishid.openinv.internal.ISpecialInventory;
import com.mojang.authlib.GameProfile;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import net.minecraft.server.v1_16_R3.ChatComponentText;
import net.minecraft.server.v1_16_R3.ChatMessageType;
import net.minecraft.server.v1_16_R3.Container;
import net.minecraft.server.v1_16_R3.Containers;
import net.minecraft.server.v1_16_R3.Entity;
import net.minecraft.server.v1_16_R3.EntityHuman;
import net.minecraft.server.v1_16_R3.EntityPlayer;
import net.minecraft.server.v1_16_R3.MinecraftServer;
import net.minecraft.server.v1_16_R3.NBTCompressedStreamTools;
import net.minecraft.server.v1_16_R3.NBTTagCompound;
import net.minecraft.server.v1_16_R3.PacketPlayOutChat;
import net.minecraft.server.v1_16_R3.PacketPlayOutOpenWindow;
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
import net.minecraft.server.v1_16_R3.PlayerInventory;
import net.minecraft.server.v1_16_R3.SystemUtils;
import net.minecraft.server.v1_16_R3.World;
import net.minecraft.server.v1_16_R3.WorldNBTStorage;
import net.minecraft.server.v1_16_R3.WorldServer;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftContainer;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
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;
public class PlayerDataManager implements IPlayerDataManager {
private @Nullable Field bukkitEntity;
public PlayerDataManager() {
try {
bukkitEntity = Entity.class.getDeclaredField("bukkitEntity");
} catch (NoSuchFieldException e) {
System.out.println("Unable to obtain field to inject custom save process - players' mounts may be deleted when loaded.");
e.printStackTrace();
bukkitEntity = null;
}
}
@NotNull
public static EntityPlayer getHandle(final Player player) {
if (player instanceof CraftPlayer) {
return ((CraftPlayer) player).getHandle();
}
Server server = player.getServer();
EntityPlayer nmsPlayer = null;
if (server instanceof CraftServer) {
nmsPlayer = ((CraftServer) server).getHandle().getPlayer(player.getName());
}
if (nmsPlayer == null) {
// Could use reflection to examine fields, but it's honestly not worth the bother.
throw new RuntimeException("Unable to fetch EntityPlayer from provided Player implementation");
}
return nmsPlayer;
}
@Nullable
@Override
public Player loadPlayer(@NotNull final OfflinePlayer offline) {
// Ensure player has data
if (!offline.hasPlayedBefore()) {
return null;
}
// Create a profile and entity to load the player data
// See net.minecraft.server.PlayerList#attemptLogin
GameProfile profile = new GameProfile(offline.getUniqueId(),
offline.getName() != null ? offline.getName() : offline.getUniqueId().toString());
MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
WorldServer worldServer = server.getWorldServer(World.OVERWORLD);
if (worldServer == null) {
return null;
}
EntityPlayer entity = new EntityPlayer(server, worldServer, profile, new PlayerInteractManager(worldServer));
try {
injectPlayer(entity);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
// Get the bukkit entity
Player target = entity.getBukkitEntity();
if (target != null) {
// Load data
target.loadData();
}
// Return the entity
return target;
}
void injectPlayer(EntityPlayer player) throws IllegalAccessException {
if (bukkitEntity == null) {
return;
}
bukkitEntity.setAccessible(true);
bukkitEntity.set(player, new CraftPlayer(player.server.server, player) {
@Override
public void saveData() {
super.saveData();
// See net.minecraft.server.WorldNBTStorage#save(EntityPlayer)
try {
WorldNBTStorage worldNBTStorage = player.server.getPlayerList().playerFileData;
NBTTagCompound playerData = player.save(new NBTTagCompound());
if (!isOnline()) {
// Special case: save old vehicle data
NBTTagCompound oldData = worldNBTStorage.load(player);
if (oldData != null && oldData.hasKeyOfType("RootVehicle", 10)) {
// See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound)
playerData.set("RootVehicle", oldData.getCompound("RootVehicle"));
}
}
File file = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat.tmp");
File file1 = new File(worldNBTStorage.getPlayerDir(), player.getUniqueIDString() + ".dat");
NBTCompressedStreamTools.a(playerData, new FileOutputStream(file));
if (file1.exists() && !file1.delete() || !file.renameTo(file1)) {
LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString());
}
} catch (Exception e) {
LogManager.getLogger().warn("Failed to save player data for {}", player.getDisplayName().getString());
}
}
});
}
@NotNull
@Override
public Player inject(@NotNull Player player) {
try {
EntityPlayer nmsPlayer = getHandle(player);
injectPlayer(nmsPlayer);
return nmsPlayer.getBukkitEntity();
} catch (IllegalAccessException e) {
e.printStackTrace();
return player;
}
}
@Nullable
@Override
public InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory) {
EntityPlayer nmsPlayer = getHandle(player);
if (nmsPlayer.playerConnection == null) {
return null;
}
String title;
if (inventory instanceof SpecialEnderChest) {
HumanEntity owner = (HumanEntity) ((SpecialEnderChest) inventory).getBukkitOwner();
title = OpenInv.getPlugin(OpenInv.class).getLocalizedMessage(player, "container.enderchest", "%player%", owner.getName());
if (title == null) {
title = owner.getName() + "'s Ender Chest";
}
} else if (inventory instanceof SpecialPlayerInventory) {
EntityHuman owner = ((PlayerInventory) inventory).player;
title = OpenInv.getPlugin(OpenInv.class).getLocalizedMessage(player, "container.player", "%player%", owner.getName());
if (title == null) {
title = owner.getName() + "'s Inventory";
}
} else {
return player.openInventory(inventory.getBukkitInventory());
}
String finalTitle = title;
Container container = new CraftContainer(new InventoryView() {
@Override
public @NotNull Inventory getTopInventory() {
return inventory.getBukkitInventory();
}
@Override
public @NotNull Inventory getBottomInventory() {
return player.getInventory();
}
@Override
public @NotNull HumanEntity getPlayer() {
return player;
}
@Override
public @NotNull InventoryType getType() {
return inventory.getBukkitInventory().getType();
}
@Override
public @NotNull String getTitle() {
return finalTitle;
}
}, nmsPlayer, nmsPlayer.nextContainerCounter()) {
@Override
public Containers<?> getType() {
switch (inventory.getBukkitInventory().getSize()) {
case 9:
return Containers.GENERIC_9X1;
case 18:
return Containers.GENERIC_9X2;
case 27:
default:
return Containers.GENERIC_9X3;
case 36:
return Containers.GENERIC_9X4;
case 41: // PLAYER
case 45:
return Containers.GENERIC_9X5;
case 54:
return Containers.GENERIC_9X6;
}
}
};
container.setTitle(new ChatComponentText(title));
container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container);
if (container == null) {
return null;
}
nmsPlayer.playerConnection.sendPacket(new PacketPlayOutOpenWindow(container.windowId, container.getType(),
new ChatComponentText(container.getBukkitView().getTitle())));
nmsPlayer.activeContainer = container;
container.addSlotListener(nmsPlayer);
return container.getBukkitView();
}
@Override
public void sendSystemMessage(@NotNull Player player, @NotNull String message) {
int newline = message.indexOf('\n');
if (newline != -1) {
// No newlines in action bar chat.
message = message.substring(0, newline);
}
if (message.isEmpty()) {
return;
}
EntityPlayer nmsPlayer = getHandle(player);
// For action bar chat, color codes are still supported but JSON text color is not allowed. Do not convert text.
if (nmsPlayer.playerConnection != null) {
nmsPlayer.playerConnection.sendPacket(new PacketPlayOutChat(new ChatComponentText(message), ChatMessageType.GAME_INFO, SystemUtils.b));
}
}
}

View File

@@ -0,0 +1,256 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_16_R3;
import com.lishid.openinv.internal.ISpecialEnderChest;
import java.util.List;
import net.minecraft.server.v1_16_R3.AutoRecipeStackManager;
import net.minecraft.server.v1_16_R3.ContainerUtil;
import net.minecraft.server.v1_16_R3.EntityHuman;
import net.minecraft.server.v1_16_R3.EntityPlayer;
import net.minecraft.server.v1_16_R3.IInventoryListener;
import net.minecraft.server.v1_16_R3.InventoryEnderChest;
import net.minecraft.server.v1_16_R3.ItemStack;
import net.minecraft.server.v1_16_R3.NonNullList;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftInventory;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SpecialEnderChest extends InventoryEnderChest implements ISpecialEnderChest {
private final CraftInventory inventory;
private EntityPlayer owner;
private NonNullList<ItemStack> items;
private boolean playerOnline;
public SpecialEnderChest(final Player player, final Boolean online) {
super(PlayerDataManager.getHandle(player));
this.inventory = new CraftInventory(this);
this.owner = PlayerDataManager.getHandle(player);
this.playerOnline = online;
this.items = this.owner.getEnderChest().items;
}
@Override
public @NotNull CraftInventory getBukkitInventory() {
return inventory;
}
@Override
public boolean isInUse() {
return !this.getViewers().isEmpty();
}
@Override
public void setPlayerOffline() {
this.playerOnline = false;
}
@Override
public void setPlayerOnline(@NotNull final Player player) {
if (!this.playerOnline) {
try {
this.owner = PlayerDataManager.getHandle(player);
InventoryEnderChest enderChest = owner.getEnderChest();
for (int i = 0; i < enderChest.getSize(); ++i) {
enderChest.setItem(i, this.items.get(i));
}
this.items = enderChest.items;
} catch (Exception ignored) {}
this.playerOnline = true;
}
}
@Override
public void update() {
this.owner.getEnderChest().update();
}
@Override
public List<ItemStack> getContents() {
return this.items;
}
@Override
public void onOpen(CraftHumanEntity who) {
this.owner.getEnderChest().onOpen(who);
}
@Override
public void onClose(CraftHumanEntity who) {
this.owner.getEnderChest().onClose(who);
}
@Override
public List<HumanEntity> getViewers() {
return this.owner.getEnderChest().getViewers();
}
@Override
public void setMaxStackSize(int i) {
this.owner.getEnderChest().setMaxStackSize(i);
}
@Override
public InventoryHolder getOwner() {
return this.owner.getEnderChest().getOwner();
}
@Override
public @Nullable Location getLocation() {
return null;
}
@Override
public void a(IInventoryListener iinventorylistener) {
this.owner.getEnderChest().a(iinventorylistener);
}
@Override
public void b(IInventoryListener iinventorylistener) {
this.owner.getEnderChest().b(iinventorylistener);
}
@Override
public ItemStack getItem(int i) {
return i >= 0 && i < this.items.size() ? this.items.get(i) : ItemStack.b;
}
@Override
public ItemStack splitStack(int i, int j) {
ItemStack itemstack = ContainerUtil.a(this.items, i, j);
if (!itemstack.isEmpty()) {
this.update();
}
return itemstack;
}
@Override
public ItemStack a(ItemStack itemstack) {
ItemStack itemstack1 = itemstack.cloneItemStack();
for (int i = 0; i < this.getSize(); ++i) {
ItemStack itemstack2 = this.getItem(i);
if (itemstack2.isEmpty()) {
this.setItem(i, itemstack1);
this.update();
return ItemStack.b;
}
if (ItemStack.c(itemstack2, itemstack1)) {
int j = Math.min(this.getMaxStackSize(), itemstack2.getMaxStackSize());
int k = Math.min(itemstack1.getCount(), j - itemstack2.getCount());
if (k > 0) {
itemstack2.add(k);
itemstack1.subtract(k);
if (itemstack1.isEmpty()) {
this.update();
return ItemStack.b;
}
}
}
}
if (itemstack1.getCount() != itemstack.getCount()) {
this.update();
}
return itemstack1;
}
@Override
public ItemStack splitWithoutUpdate(int i) {
ItemStack itemstack = this.items.get(i);
if (itemstack.isEmpty()) {
return ItemStack.b;
} else {
this.items.set(i, ItemStack.b);
return itemstack;
}
}
@Override
public void setItem(int i, ItemStack itemstack) {
this.items.set(i, itemstack);
if (!itemstack.isEmpty() && itemstack.getCount() > this.getMaxStackSize()) {
itemstack.setCount(this.getMaxStackSize());
}
this.update();
}
@Override
public int getSize() {
return this.owner.getEnderChest().getSize();
}
@Override
public boolean isEmpty() {
for (ItemStack itemstack : this.items) {
if (!itemstack.isEmpty()) {
return false;
}
}
return true;
}
@Override
public int getMaxStackSize() {
return 64;
}
@Override
public boolean a(EntityHuman entityhuman) {
return true;
}
@Override
public void startOpen(EntityHuman entityhuman) {
}
@Override
public void closeContainer(EntityHuman entityhuman) {
}
@Override
public boolean b(int i, ItemStack itemstack) {
return true;
}
@Override
public void clear() {
this.items.clear();
}
@Override
public void a(AutoRecipeStackManager autorecipestackmanager) {
for (ItemStack itemstack : this.items) {
autorecipestackmanager.b(itemstack);
}
}
}

View File

@@ -0,0 +1,733 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.internal.v1_16_R3;
import com.google.common.collect.ImmutableList;
import com.lishid.openinv.internal.ISpecialPlayerInventory;
import java.util.Iterator;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import net.minecraft.server.v1_16_R3.AutoRecipeStackManager;
import net.minecraft.server.v1_16_R3.ChatMessage;
import net.minecraft.server.v1_16_R3.ContainerUtil;
import net.minecraft.server.v1_16_R3.CrashReport;
import net.minecraft.server.v1_16_R3.CrashReportSystemDetails;
import net.minecraft.server.v1_16_R3.DamageSource;
import net.minecraft.server.v1_16_R3.EntityHuman;
import net.minecraft.server.v1_16_R3.EntityPlayer;
import net.minecraft.server.v1_16_R3.EnumItemSlot;
import net.minecraft.server.v1_16_R3.IBlockData;
import net.minecraft.server.v1_16_R3.IChatBaseComponent;
import net.minecraft.server.v1_16_R3.IInventory;
import net.minecraft.server.v1_16_R3.Item;
import net.minecraft.server.v1_16_R3.ItemArmor;
import net.minecraft.server.v1_16_R3.ItemStack;
import net.minecraft.server.v1_16_R3.NBTTagCompound;
import net.minecraft.server.v1_16_R3.NBTTagList;
import net.minecraft.server.v1_16_R3.NonNullList;
import net.minecraft.server.v1_16_R3.PacketPlayOutSetSlot;
import net.minecraft.server.v1_16_R3.PlayerInventory;
import net.minecraft.server.v1_16_R3.ReportedException;
import net.minecraft.server.v1_16_R3.World;
import org.bukkit.Location;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftInventory;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryHolder;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory {
private final CraftInventory inventory;
private boolean playerOnline;
private EntityHuman player;
private NonNullList<ItemStack> items, armor, extraSlots;
private List<NonNullList<ItemStack>> f;
public SpecialPlayerInventory(final Player bukkitPlayer, final Boolean online) {
super(PlayerDataManager.getHandle(bukkitPlayer));
this.inventory = new CraftInventory(this);
this.playerOnline = online;
this.player = super.player;
this.items = this.player.inventory.items;
this.armor = this.player.inventory.armor;
this.extraSlots = this.player.inventory.extraSlots;
this.f = ImmutableList.of(this.items, this.armor, this.extraSlots);
}
@Override
public void setPlayerOnline(@NotNull final Player player) {
if (!this.playerOnline) {
EntityPlayer entityPlayer = PlayerDataManager.getHandle(player);
entityPlayer.inventory.transaction.addAll(this.transaction);
this.player = entityPlayer;
for (int i = 0; i < getSize(); ++i) {
this.player.inventory.setItem(i, getRawItem(i));
}
this.player.inventory.itemInHandIndex = this.itemInHandIndex;
this.items = this.player.inventory.items;
this.armor = this.player.inventory.armor;
this.extraSlots = this.player.inventory.extraSlots;
this.f = ImmutableList.of(this.items, this.armor, this.extraSlots);
this.playerOnline = true;
}
}
@Override
public boolean a(final EntityHuman entityhuman) {
return true;
}
@Override
public @NotNull CraftInventory getBukkitInventory() {
return this.inventory;
}
@Override
public ItemStack getItem(int i) {
List<ItemStack> list = this.items;
if (i >= list.size()) {
i -= list.size();
list = this.armor;
} else {
i = this.getReversedItemSlotNum(i);
}
if (i >= list.size()) {
i -= list.size();
list = this.extraSlots;
} else if (list == this.armor) {
i = this.getReversedArmorSlotNum(i);
}
if (i >= list.size()) {
return ItemStack.b;
}
return list.get(i);
}
private ItemStack getRawItem(int i) {
NonNullList<ItemStack> list = null;
for (NonNullList<ItemStack> next : this.f) {
if (i < next.size()) {
list = next;
break;
}
i -= next.size();
}
return list == null ? ItemStack.b : list.get(i);
}
@Override
public IChatBaseComponent getDisplayName() {
return new ChatMessage(this.player.getName());
}
@Override
public boolean hasCustomName() {
return false;
}
private int getReversedArmorSlotNum(final int i) {
if (i == 0) {
return 3;
}
if (i == 1) {
return 2;
}
if (i == 2) {
return 1;
}
if (i == 3) {
return 0;
}
return i;
}
private int getReversedItemSlotNum(final int i) {
if (i >= 27) {
return i - 27;
}
return i + 9;
}
@Override
public int getSize() {
return 45;
}
@Override
public boolean isInUse() {
return !this.getViewers().isEmpty();
}
@Override
public void setItem(int i, final ItemStack itemstack) {
List<ItemStack> list = this.items;
if (i >= list.size()) {
i -= list.size();
list = this.armor;
} else {
i = this.getReversedItemSlotNum(i);
}
if (i >= list.size()) {
i -= list.size();
list = this.extraSlots;
} else if (list == this.armor) {
i = this.getReversedArmorSlotNum(i);
}
if (i >= list.size()) {
this.player.drop(itemstack, true);
return;
}
list.set(i, itemstack);
}
@Override
public void setPlayerOffline() {
this.playerOnline = false;
}
@Override
public ItemStack splitStack(int i, final int j) {
List<ItemStack> list = this.items;
if (i >= list.size()) {
i -= list.size();
list = this.armor;
} else {
i = this.getReversedItemSlotNum(i);
}
if (i >= list.size()) {
i -= list.size();
list = this.extraSlots;
} else if (list == this.armor) {
i = this.getReversedArmorSlotNum(i);
}
if (i >= list.size()) {
return ItemStack.b;
}
return list.get(i).isEmpty() ? ItemStack.b : ContainerUtil.a(list, i, j);
}
@Override
public ItemStack splitWithoutUpdate(int i) {
List<ItemStack> list = this.items;
if (i >= list.size()) {
i -= list.size();
list = this.armor;
} else {
i = this.getReversedItemSlotNum(i);
}
if (i >= list.size()) {
i -= list.size();
list = this.extraSlots;
} else if (list == this.armor) {
i = this.getReversedArmorSlotNum(i);
}
if (i >= list.size()) {
return ItemStack.b;
}
if (!list.get(i).isEmpty()) {
ItemStack itemstack = list.get(i);
list.set(i, ItemStack.b);
return itemstack;
}
return ItemStack.b;
}
@Override
public List<ItemStack> getContents() {
return this.f.stream().flatMap(List::stream).collect(Collectors.toList());
}
@Override
public List<ItemStack> getArmorContents() {
return this.armor;
}
@Override
public void onOpen(CraftHumanEntity who) {
this.transaction.add(who);
}
@Override
public void onClose(CraftHumanEntity who) {
this.transaction.remove(who);
}
@Override
public List<HumanEntity> getViewers() {
return this.transaction;
}
@Override
public InventoryHolder getOwner() {
return this.player.getBukkitEntity();
}
@Override
public Location getLocation() {
return this.player.getBukkitEntity().getLocation();
}
@Override
public ItemStack getItemInHand() {
return d(this.itemInHandIndex) ? this.items.get(this.itemInHandIndex) : ItemStack.b;
}
private boolean isSimilarAndNotFull(ItemStack itemstack, ItemStack itemstack1) {
return !itemstack.isEmpty() && this.b(itemstack, itemstack1) && itemstack.isStackable() && itemstack.getCount() < itemstack.getMaxStackSize() && itemstack.getCount() < this.getMaxStackSize();
}
private boolean b(ItemStack itemstack, ItemStack itemstack1) {
return itemstack.getItem() == itemstack1.getItem() && ItemStack.equals(itemstack, itemstack1);
}
@Override
public int canHold(ItemStack itemstack) {
int remains = itemstack.getCount();
for (int i = 0; i < this.items.size(); ++i) {
ItemStack itemstack1 = this.getItem(i);
if (itemstack1.isEmpty()) {
return itemstack.getCount();
}
if (!this.isSimilarAndNotFull(itemstack, itemstack1)) {
remains -= Math.min(itemstack1.getMaxStackSize(), this.getMaxStackSize()) - itemstack1.getCount();
}
if (remains <= 0) {
return itemstack.getCount();
}
}
ItemStack offhandItemStack = this.getItem(this.items.size() + this.armor.size());
if (this.isSimilarAndNotFull(offhandItemStack, itemstack)) {
remains -= Math.min(offhandItemStack.getMaxStackSize(), this.getMaxStackSize()) - offhandItemStack.getCount();
}
return itemstack.getCount() - remains;
}
@Override
public int getFirstEmptySlotIndex() {
for (int i = 0; i < this.items.size(); ++i) {
if (this.items.get(i).isEmpty()) {
return i;
}
}
return -1;
}
@Override
public void c(int i) {
this.itemInHandIndex = this.i();
ItemStack itemstack = this.items.get(this.itemInHandIndex);
this.items.set(this.itemInHandIndex, this.items.get(i));
this.items.set(i, itemstack);
}
@Override
public int c(ItemStack itemstack) {
for (int i = 0; i < this.items.size(); ++i) {
ItemStack itemstack1 = this.items.get(i);
if (!this.items.get(i).isEmpty() && this.b(itemstack, this.items.get(i)) && !this.items.get(i).f() && !itemstack1.hasEnchantments() && !itemstack1.hasName()) {
return i;
}
}
return -1;
}
@Override
public int i() {
int i;
int j;
for (j = 0; j < 9; ++j) {
i = (this.itemInHandIndex + j) % 9;
if (this.items.get(i).isEmpty()) {
return i;
}
}
for (j = 0; j < 9; ++j) {
i = (this.itemInHandIndex + j) % 9;
if (!this.items.get(i).hasEnchantments()) {
return i;
}
}
return this.itemInHandIndex;
}
@Override
public int a(Predicate<ItemStack> predicate, int i, IInventory iinventory) {
byte b0 = 0;
boolean flag = i == 0;
int j = b0 + ContainerUtil.a(this, predicate, i - b0, flag);
j += ContainerUtil.a(iinventory, predicate, i - j, flag);
j += ContainerUtil.a(this.getCarried(), predicate, i - j, flag);
if (this.getCarried().isEmpty()) {
this.setCarried(ItemStack.b);
}
return j;
}
private int i(ItemStack itemstack) {
int i = this.firstPartial(itemstack);
if (i == -1) {
i = this.getFirstEmptySlotIndex();
}
return i == -1 ? itemstack.getCount() : this.d(i, itemstack);
}
private int d(int i, ItemStack itemstack) {
Item item = itemstack.getItem();
int j = itemstack.getCount();
ItemStack itemstack1 = this.getItem(i);
if (itemstack1.isEmpty()) {
itemstack1 = new ItemStack(item, 0);
NBTTagCompound tag = itemstack.getTag();
if (tag != null) {
itemstack1.setTag(tag.clone());
}
this.setItem(i, itemstack1);
}
int k = j;
if (j > itemstack1.getMaxStackSize() - itemstack1.getCount()) {
k = itemstack1.getMaxStackSize() - itemstack1.getCount();
}
if (k > this.getMaxStackSize() - itemstack1.getCount()) {
k = this.getMaxStackSize() - itemstack1.getCount();
}
if (k != 0) {
j -= k;
itemstack1.add(k);
itemstack1.d(5);
}
return j;
}
@Override
public int firstPartial(ItemStack itemstack) {
if (this.isSimilarAndNotFull(this.getItem(this.itemInHandIndex), itemstack)) {
return this.itemInHandIndex;
} else if (this.isSimilarAndNotFull(this.getItem(40), itemstack)) {
return 40;
} else {
for (int i = 0; i < this.items.size(); ++i) {
if (this.isSimilarAndNotFull(this.items.get(i), itemstack)) {
return i;
}
}
return -1;
}
}
@Override
public void j() {
for (List<ItemStack> itemStacks : this.f) {
for (int i = 0; i < itemStacks.size(); ++i) {
if (!itemStacks.get(i).isEmpty()) {
itemStacks.get(i).a(this.player.world, this.player, i, this.itemInHandIndex == i);
}
}
}
}
@Override
public boolean pickup(ItemStack itemstack) {
return this.c(-1, itemstack);
}
@Override
public boolean c(int i, ItemStack itemstack) {
if (itemstack.isEmpty()) {
return false;
} else {
try {
if (itemstack.f()) {
if (i == -1) {
i = this.getFirstEmptySlotIndex();
}
if (i >= 0) {
this.items.set(i, itemstack.cloneItemStack());
this.items.get(i).d(5);
itemstack.setCount(0);
return true;
} else if (this.player.abilities.canInstantlyBuild) {
itemstack.setCount(0);
return true;
} else {
return false;
}
} else {
int j;
do {
j = itemstack.getCount();
if (i == -1) {
itemstack.setCount(this.i(itemstack));
} else {
itemstack.setCount(this.d(i, itemstack));
}
} while(!itemstack.isEmpty() && itemstack.getCount() < j);
if (itemstack.getCount() == j && this.player.abilities.canInstantlyBuild) {
itemstack.setCount(0);
return true;
} else {
return itemstack.getCount() < j;
}
}
} catch (Throwable var6) {
CrashReport crashreport = CrashReport.a(var6, "Adding item to inventory");
CrashReportSystemDetails crashreportsystemdetails = crashreport.a("Item being added");
crashreportsystemdetails.a("Item ID", Item.getId(itemstack.getItem()));
crashreportsystemdetails.a("Item data", itemstack.getDamage());
crashreportsystemdetails.a("Item name", () -> itemstack.getName().getString());
throw new ReportedException(crashreport);
}
}
}
@Override
public void a(World world, ItemStack itemstack) {
if (!world.isClientSide) {
while(!itemstack.isEmpty()) {
int i = this.firstPartial(itemstack);
if (i == -1) {
i = this.getFirstEmptySlotIndex();
}
if (i == -1) {
this.player.drop(itemstack, false);
break;
}
int j = itemstack.getMaxStackSize() - this.getItem(i).getCount();
if (this.c(i, itemstack.cloneAndSubtract(j))) {
((EntityPlayer)this.player).playerConnection.sendPacket(new PacketPlayOutSetSlot(-2, i, this.getItem(i)));
}
}
}
}
@Override
public void f(ItemStack itemstack) {
for (List<ItemStack> list : this.f) {
for (int i = 0; i < list.size(); ++i) {
if (list.get(i) == itemstack) {
list.set(i, ItemStack.b);
break;
}
}
}
}
@Override
public float a(IBlockData iblockdata) {
return this.items.get(this.itemInHandIndex).a(iblockdata);
}
@Override
public NBTTagList a(NBTTagList nbttaglist) {
NBTTagCompound nbttagcompound;
int i;
for (i = 0; i < this.items.size(); ++i) {
if (!this.items.get(i).isEmpty()) {
nbttagcompound = new NBTTagCompound();
nbttagcompound.setByte("Slot", (byte) i);
this.items.get(i).save(nbttagcompound);
nbttaglist.add(nbttagcompound);
}
}
for (i = 0; i < this.armor.size(); ++i) {
if (!this.armor.get(i).isEmpty()) {
nbttagcompound = new NBTTagCompound();
nbttagcompound.setByte("Slot", (byte) (i + 100));
this.armor.get(i).save(nbttagcompound);
nbttaglist.add(nbttagcompound);
}
}
for (i = 0; i < this.extraSlots.size(); ++i) {
if (!this.extraSlots.get(i).isEmpty()) {
nbttagcompound = new NBTTagCompound();
nbttagcompound.setByte("Slot", (byte) (i + 150));
this.extraSlots.get(i).save(nbttagcompound);
nbttaglist.add(nbttagcompound);
}
}
return nbttaglist;
}
@Override
public void b(NBTTagList nbttaglist) {
this.items.clear();
this.armor.clear();
this.extraSlots.clear();
for(int i = 0; i < nbttaglist.size(); ++i) {
NBTTagCompound nbttagcompound = nbttaglist.getCompound(i);
int j = nbttagcompound.getByte("Slot") & 255;
ItemStack itemstack = ItemStack.a(nbttagcompound);
if (!itemstack.isEmpty()) {
if (j < this.items.size()) {
this.items.set(j, itemstack);
} else if (j >= 100 && j < this.armor.size() + 100) {
this.armor.set(j - 100, itemstack);
} else if (j >= 150 && j < this.extraSlots.size() + 150) {
this.extraSlots.set(j - 150, itemstack);
}
}
}
}
@Override
public boolean isEmpty() {
Iterator<ItemStack> iterator = this.items.iterator();
ItemStack itemstack;
while (iterator.hasNext()) {
itemstack = iterator.next();
if (!itemstack.isEmpty()) {
return false;
}
}
iterator = this.armor.iterator();
while (iterator.hasNext()) {
itemstack = iterator.next();
if (!itemstack.isEmpty()) {
return false;
}
}
iterator = this.extraSlots.iterator();
while (iterator.hasNext()) {
itemstack = iterator.next();
if (!itemstack.isEmpty()) {
return false;
}
}
return true;
}
@Nullable
@Override
public IChatBaseComponent getCustomName() {
return null;
}
@Override
public void a(DamageSource damagesource, float f) {
if (f > 0.0F) {
f /= 4.0F;
if (f < 1.0F) {
f = 1.0F;
}
for (int i = 0; i < this.armor.size(); ++i) {
ItemStack itemstack = this.armor.get(0);
int index = i;
if ((!damagesource.isFire() || !itemstack.getItem().u()) && itemstack.getItem() instanceof ItemArmor) {
itemstack.damage((int) f, this.player, (entityHuman) -> entityHuman.broadcastItemBreak(EnumItemSlot.a(EnumItemSlot.Function.ARMOR, index)));
}
}
}
}
@Override
public void dropContents() {
for (List<ItemStack> itemStacks : this.f) {
for (int i = 0; i < itemStacks.size(); ++i) {
ItemStack itemstack = itemStacks.get(i);
if (!itemstack.isEmpty()) {
itemStacks.set(i, ItemStack.b);
this.player.a(itemstack, true, false);
}
}
}
}
@Override
public boolean h(ItemStack itemstack) {
return this.f.stream().flatMap(List::stream).anyMatch(itemStack1 -> !itemStack1.isEmpty() && itemStack1.doMaterialsMatch(itemstack));
}
@Override
public void a(PlayerInventory playerinventory) {
for (int i = 0; i < playerinventory.getSize(); ++i) {
this.setItem(i, playerinventory.getItem(i));
}
this.itemInHandIndex = playerinventory.itemInHandIndex;
}
@Override
public void clear() {
this.f.forEach(List::clear);
}
@Override
public void a(AutoRecipeStackManager autorecipestackmanager) {
for (ItemStack itemstack : this.items) {
autorecipestackmanager.a(itemstack);
}
}
}

View File

@@ -21,7 +21,7 @@
<parent> <parent>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvinternal</artifactId> <artifactId>openinvinternal</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</parent> </parent>
<artifactId>openinvadapter1_8_R3</artifactId> <artifactId>openinvadapter1_8_R3</artifactId>
@@ -37,7 +37,7 @@
<dependency> <dependency>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvplugincore</artifactId> <artifactId>openinvplugincore</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</dependency> </dependency>
</dependencies> </dependencies>

View File

@@ -21,7 +21,7 @@
<parent> <parent>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvparent</artifactId> <artifactId>openinvparent</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</parent> </parent>
<artifactId>openinvplugincore</artifactId> <artifactId>openinvplugincore</artifactId>
@@ -31,7 +31,7 @@
<dependency> <dependency>
<groupId>com.lishid</groupId> <groupId>com.lishid</groupId>
<artifactId>openinvapi</artifactId> <artifactId>openinvapi</artifactId>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>

View File

@@ -27,9 +27,7 @@ import com.lishid.openinv.internal.IAnySilentContainer;
import com.lishid.openinv.internal.ISpecialEnderChest; import com.lishid.openinv.internal.ISpecialEnderChest;
import com.lishid.openinv.internal.ISpecialInventory; import com.lishid.openinv.internal.ISpecialInventory;
import com.lishid.openinv.internal.ISpecialPlayerInventory; import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.listeners.InventoryClickListener; import com.lishid.openinv.listeners.InventoryListener;
import com.lishid.openinv.listeners.InventoryCloseListener;
import com.lishid.openinv.listeners.InventoryDragListener;
import com.lishid.openinv.listeners.PlayerListener; import com.lishid.openinv.listeners.PlayerListener;
import com.lishid.openinv.listeners.PluginListener; import com.lishid.openinv.listeners.PluginListener;
import com.lishid.openinv.util.Cache; import com.lishid.openinv.util.Cache;
@@ -105,7 +103,6 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
if (!OpenInv.this.disableSaving() && !value.isOnline()) { if (!OpenInv.this.disableSaving() && !value.isOnline()) {
value.saveData(); value.saveData();
} }
return true;
}); });
private InternalAccessor accessor; private InternalAccessor accessor;
@@ -127,6 +124,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
if (this.inventories.containsKey(key)) { if (this.inventories.containsKey(key)) {
Iterator<HumanEntity> iterator = this.inventories.get(key).getBukkitInventory().getViewers().iterator(); Iterator<HumanEntity> iterator = this.inventories.get(key).getBukkitInventory().getViewers().iterator();
//noinspection WhileLoopReplaceableByForEach
while (iterator.hasNext()) { while (iterator.hasNext()) {
HumanEntity human = iterator.next(); HumanEntity human = iterator.next();
// If player has permission or is in the same world, allow continued access // If player has permission or is in the same world, allow continued access
@@ -140,6 +138,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
if (this.enderChests.containsKey(key)) { if (this.enderChests.containsKey(key)) {
Iterator<HumanEntity> iterator = this.enderChests.get(key).getBukkitInventory().getViewers().iterator(); Iterator<HumanEntity> iterator = this.enderChests.get(key).getBukkitInventory().getViewers().iterator();
//noinspection WhileLoopReplaceableByForEach
while (iterator.hasNext()) { while (iterator.hasNext()) {
HumanEntity human = iterator.next(); HumanEntity human = iterator.next();
if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld().equals(player.getWorld())) { if (Permissions.CROSSWORLD.hasPermission(human) || human.getWorld().equals(player.getWorld())) {
@@ -222,22 +221,18 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
return this.accessor != null && this.accessor.isSupported(); return this.accessor != null && this.accessor.isSupported();
} }
@Nullable
@Override @Override
public Player loadPlayer(@NotNull final OfflinePlayer offline) { public @Nullable Player loadPlayer(@NotNull final OfflinePlayer offline) {
String key = this.getPlayerID(offline); String key = this.getPlayerID(offline);
if (this.playerCache.containsKey(key)) { if (this.playerCache.containsKey(key)) {
return this.playerCache.get(key); return this.playerCache.get(key);
} }
// TODO: wrap Player to ensure all methods can safely be called offline Player player = offline.getPlayer();
Player loaded; if (player != null) {
this.playerCache.put(key, player);
if (offline.isOnline()) { return player;
loaded = offline.getPlayer();
this.playerCache.put(key, loaded);
return loaded;
} }
if (!this.isSupportedVersion()) { if (!this.isSupportedVersion()) {
@@ -251,33 +246,18 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
Future<Player> future = Bukkit.getScheduler().callSyncMethod(this, Future<Player> future = Bukkit.getScheduler().callSyncMethod(this,
() -> OpenInv.this.accessor.getPlayerDataManager().loadPlayer(offline)); () -> OpenInv.this.accessor.getPlayerDataManager().loadPlayer(offline));
int ticks = 0;
while (!future.isDone() && !future.isCancelled() && ticks < 10) {
++ticks;
try {
Thread.sleep(50L);
} catch (InterruptedException e) {
e.printStackTrace();
return null;
}
}
if (!future.isDone() || future.isCancelled()) {
return null;
}
try { try {
loaded = future.get(); player = future.get();
} catch (InterruptedException | ExecutionException e) { } catch (InterruptedException | ExecutionException e) {
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
if (loaded != null) { if (player != null) {
this.playerCache.put(key, loaded); this.playerCache.put(key, player);
} }
return loaded; return player;
} }
@Override @Override
@@ -317,8 +297,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
return this.languageManager.getValue(key, getLocale(sender), replacements); return this.languageManager.getValue(key, getLocale(sender), replacements);
} }
@Nullable private @Nullable String getLocale(@NotNull CommandSender sender) {
private String getLocale(@NotNull CommandSender sender) {
if (sender instanceof Player) { if (sender instanceof Player) {
return this.accessor.getPlayerDataManager().getLocale((Player) sender); return this.accessor.getPlayerDataManager().getLocale((Player) sender);
} else { } else {
@@ -369,10 +348,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
// Register listeners // Register listeners
pm.registerEvents(new PlayerListener(this), this); pm.registerEvents(new PlayerListener(this), this);
pm.registerEvents(new PluginListener(this), this); pm.registerEvents(new PluginListener(this), this);
pm.registerEvents(new InventoryClickListener(), this); pm.registerEvents(new InventoryListener(this), this);
pm.registerEvents(new InventoryCloseListener(this), this);
// Bukkit will handle missing events for us, attempt to register InventoryDragEvent without a version check
pm.registerEvents(new InventoryDragListener(), this);
// Register commands to their executors // Register commands to their executors
OpenInvCommand openInv = new OpenInvCommand(this); OpenInvCommand openInv = new OpenInvCommand(this);
@@ -405,8 +381,8 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
@Override @Override
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) {
if (!this.accessor.isSupported()) { if (!this.accessor.isSupported()) {
sender.sendMessage("Your version of CraftBukkit (" + this.accessor.getVersion() + ") is not supported."); sender.sendMessage("Your server version (" + this.accessor.getVersion() + ") is not supported.");
sender.sendMessage("If this version is a recent release, check for an update."); sender.sendMessage("Please check https://github.com/lishid/OpenInv/releases for an update.");
return true; return true;
} }
return false; return false;

View File

@@ -21,7 +21,7 @@ import com.lishid.openinv.util.TabCompleter;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Function; import java.util.function.Predicate;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@@ -46,7 +46,7 @@ public class ContainerSettingCommand implements TabExecutor {
Player player = (Player) sender; Player player = (Player) sender;
boolean any = command.getName().startsWith("any"); boolean any = command.getName().startsWith("any");
Function<Player, Boolean> getSetting = any ? plugin::getPlayerAnyChestStatus : plugin::getPlayerSilentChestStatus; Predicate<Player> getSetting = any ? plugin::getPlayerAnyChestStatus : plugin::getPlayerSilentChestStatus;
BiConsumer<OfflinePlayer, Boolean> setSetting = any ? plugin::setPlayerAnyChestStatus : plugin::setPlayerSilentChestStatus; BiConsumer<OfflinePlayer, Boolean> setSetting = any ? plugin::setPlayerAnyChestStatus : plugin::setPlayerSilentChestStatus;
if (args.length > 0) { if (args.length > 0) {
@@ -62,12 +62,12 @@ public class ContainerSettingCommand implements TabExecutor {
} }
} else { } else {
setSetting.accept(player, !getSetting.apply(player)); setSetting.accept(player, !getSetting.test(player));
} }
String onOff = plugin.getLocalizedMessage(player, getSetting.apply(player) ? "messages.info.on" : "messages.info.off"); String onOff = plugin.getLocalizedMessage(player, getSetting.test(player) ? "messages.info.on" : "messages.info.off");
if (onOff == null) { if (onOff == null) {
onOff = String.valueOf(getSetting.apply(player)); onOff = String.valueOf(getSetting.test(player));
} }
plugin.sendMessage(sender, "messages.info.settingState","%setting%", any ? "AnyContainer" : "SilentContainer", "%state%", onOff); plugin.sendMessage(sender, "messages.info.settingState","%setting%", any ? "AnyContainer" : "SilentContainer", "%state%", onOff);

View File

@@ -31,6 +31,7 @@ import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/** /**
* Command adding the ability to search online players' inventories for enchantments of a specific * Command adding the ability to search online players' inventories for enchantments of a specific
@@ -124,8 +125,9 @@ public class SearchEnchantCommand implements TabExecutor {
return true; return true;
} }
private boolean containsEnchantment(Inventory inventory, Enchantment enchant, int minLevel) { private boolean containsEnchantment(Inventory inventory, @Nullable Enchantment enchant, int minLevel) {
for (ItemStack item : inventory.getContents()) { for (ItemStack item : inventory.getContents()) {
//noinspection ConstantConditions // Spigot improperly annotated, should be ItemStack @NotNull []
if (item == null || item.getType() == Material.AIR) { if (item == null || item.getType() == Material.AIR) {
continue; continue;
} }

View File

@@ -1,40 +0,0 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.listeners;
import com.lishid.openinv.util.InventoryAccess;
import com.lishid.openinv.util.Permissions;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.inventory.Inventory;
public class InventoryClickListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onInventoryClick(InventoryClickEvent event) {
HumanEntity entity = event.getWhoClicked();
Inventory inventory = event.getInventory();
if (InventoryAccess.isPlayerInventory(inventory) && !Permissions.EDITINV.hasPermission(entity)
|| InventoryAccess.isEnderChest(inventory) && !Permissions.EDITENDER.hasPermission(entity)) {
event.setCancelled(true);
}
}
}

View File

@@ -1,46 +0,0 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.listeners;
import com.lishid.openinv.IOpenInv;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryCloseEvent;
public class InventoryCloseListener implements Listener {
private final IOpenInv plugin;
public InventoryCloseListener(final IOpenInv plugin) {
this.plugin = plugin;
}
@EventHandler
public void onInventoryClose(final InventoryCloseEvent event) {
if (!(event.getPlayer() instanceof Player)) {
return;
}
Player player = (Player) event.getPlayer();
if (this.plugin.getPlayerSilentChestStatus(player)) {
this.plugin.getAnySilentContainer().deactivateContainer(player);
}
}
}

View File

@@ -1,45 +0,0 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.listeners;
import com.lishid.openinv.util.InventoryAccess;
import com.lishid.openinv.util.Permissions;
import org.bukkit.entity.HumanEntity;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.inventory.Inventory;
/**
* Listener for InventoryDragEvents to prevent unpermitted modification of special inventories.
*
* @author Jikoo
*/
public class InventoryDragListener implements Listener {
@EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = true)
public void onInventoryDrag(InventoryDragEvent event) {
HumanEntity entity = event.getWhoClicked();
Inventory inventory = event.getInventory();
if (InventoryAccess.isPlayerInventory(inventory) && !Permissions.EDITINV.hasPermission(entity)
|| InventoryAccess.isEnderChest(inventory) && !Permissions.EDITENDER.hasPermission(entity)) {
event.setCancelled(true);
}
}
}

View File

@@ -0,0 +1,94 @@
/*
* Copyright (C) 2011-2020 lishid. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.lishid.openinv.listeners;
import com.lishid.openinv.IOpenInv;
import com.lishid.openinv.util.InventoryAccess;
import com.lishid.openinv.util.Permissions;
import org.bukkit.GameMode;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryInteractEvent;
import org.bukkit.inventory.Inventory;
/**
* Listener for inventory-related events to prevent modification of inventories where not allowed.
*
* @author Jikoo
*/
public class InventoryListener implements Listener {
private final IOpenInv plugin;
public InventoryListener(final IOpenInv plugin) {
this.plugin = plugin;
}
@EventHandler
public void onInventoryClose(final InventoryCloseEvent event) {
if (!(event.getPlayer() instanceof Player)) {
return;
}
Player player = (Player) event.getPlayer();
if (this.plugin.getPlayerSilentChestStatus(player)) {
this.plugin.getAnySilentContainer().deactivateContainer(player);
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onInventoryClick(InventoryClickEvent event) {
onInventoryInteract(event);
}
@EventHandler(priority = EventPriority.LOWEST)
public void onInventoryDrag(InventoryDragEvent event) {
onInventoryInteract(event);
}
private void onInventoryInteract(InventoryInteractEvent event) {
HumanEntity entity = event.getWhoClicked();
if (Permissions.SPECTATE.hasPermission(entity) && entity.getGameMode() == GameMode.SPECTATOR) {
event.setCancelled(false);
}
if (event.isCancelled()) {
return;
}
Inventory inventory = event.getInventory();
if (InventoryAccess.isPlayerInventory(inventory)) {
if (!Permissions.EDITINV.hasPermission(entity)) {
event.setCancelled(true);
}
} else if (InventoryAccess.isEnderChest(inventory)) {
if (!Permissions.EDITENDER.hasPermission(entity)) {
event.setCancelled(true);
}
}
}
}

View File

@@ -54,6 +54,12 @@ public class PlayerListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) { public void onPlayerInteract(PlayerInteractEvent event) {
// Do not cancel 3rd party plugins' custom events
if (!PlayerInteractEvent.class.equals(event.getClass())) {
return;
}
if (event.getAction() != Action.RIGHT_CLICK_BLOCK || event.getPlayer().isSneaking() if (event.getAction() != Action.RIGHT_CLICK_BLOCK || event.getPlayer().isSneaking()
|| event.useInteractedBlock() == Result.DENY || event.getClickedBlock() == null || event.useInteractedBlock() == Result.DENY || event.getClickedBlock() == null
|| !plugin.getAnySilentContainer().isAnySilentContainer(event.getClickedBlock())) { || !plugin.getAnySilentContainer().isAnySilentContainer(event.getClickedBlock())) {

View File

@@ -24,7 +24,8 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
import java.util.function.Function; import java.util.function.Consumer;
import java.util.function.Predicate;
/** /**
* A minimal thread-safe time-based cache implementation backed by a HashMap and TreeMultimap. * A minimal thread-safe time-based cache implementation backed by a HashMap and TreeMultimap.
@@ -36,16 +37,17 @@ public class Cache<K, V> {
private final Map<K, V> internal; private final Map<K, V> internal;
private final Multimap<Long, K> expiry; private final Multimap<Long, K> expiry;
private final long retention; private final long retention;
private final Function<V, Boolean> inUseCheck, postRemoval; private final Predicate<V> inUseCheck;
private final Consumer<V> postRemoval;
/** /**
* Constructs a Cache with the specified retention duration, in use function, and post-removal function. * Constructs a Cache with the specified retention duration, in use function, and post-removal function.
* *
* @param retention duration after which keys are automatically invalidated if not in use * @param retention duration after which keys are automatically invalidated if not in use
* @param inUseCheck Function used to check if a key is considered in use * @param inUseCheck Predicate used to check if a key is considered in use
* @param postRemoval Function used to perform any operations required when a key is invalidated * @param postRemoval Consumer used to perform any operations required when a key is invalidated
*/ */
public Cache(final long retention, final Function<V, Boolean> inUseCheck, final Function<V, Boolean> postRemoval) { public Cache(final long retention, final Predicate<V> inUseCheck, final Consumer<V> postRemoval) {
this.internal = new HashMap<>(); this.internal = new HashMap<>();
this.expiry = TreeMultimap.create(Long::compareTo, (k1, k2) -> Objects.equals(k1, k2) ? 0 : 1); this.expiry = TreeMultimap.create(Long::compareTo, (k1, k2) -> Objects.equals(k1, k2) ? 0 : 1);
@@ -136,7 +138,7 @@ public class Cache<K, V> {
public void invalidateAll() { public void invalidateAll() {
synchronized (this.internal) { synchronized (this.internal) {
for (V value : this.internal.values()) { for (V value : this.internal.values()) {
this.postRemoval.apply(value); this.postRemoval.accept(value);
} }
this.expiry.clear(); this.expiry.clear();
this.internal.clear(); this.internal.clear();
@@ -161,7 +163,7 @@ public class Cache<K, V> {
iterator.remove(); iterator.remove();
if (this.inUseCheck.apply(this.internal.get(entry.getValue()))) { if (this.inUseCheck.test(this.internal.get(entry.getValue()))) {
inUse.add(entry.getValue()); inUse.add(entry.getValue());
continue; continue;
} }
@@ -172,7 +174,7 @@ public class Cache<K, V> {
continue; continue;
} }
this.postRemoval.apply(value); this.postRemoval.accept(value);
} }
long nextExpiry = now + this.retention; long nextExpiry = now + this.retention;

View File

@@ -24,7 +24,6 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import org.bukkit.OfflinePlayer; import org.bukkit.OfflinePlayer;
import org.bukkit.configuration.ConfigurationSection; import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.scheduler.BukkitRunnable;
public class ConfigUpdater { public class ConfigUpdater {
@@ -36,7 +35,8 @@ public class ConfigUpdater {
public void checkForUpdates() { public void checkForUpdates() {
final int version = plugin.getConfig().getInt("config-version", 1); final int version = plugin.getConfig().getInt("config-version", 1);
if (version >= plugin.getConfig().getDefaults().getInt("config-version")) { ConfigurationSection defaults = plugin.getConfig().getDefaults();
if (defaults == null || version >= defaults.getInt("config-version")) {
return; return;
} }
@@ -50,87 +50,72 @@ public class ConfigUpdater {
plugin.getLogger().warning("Could not back up config.yml before updating!"); plugin.getLogger().warning("Could not back up config.yml before updating!");
} }
new BukkitRunnable() { plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
@Override if (version < 2) {
public void run() { updateConfig1To2();
if (version < 2) {
updateConfig1To2();
}
if (version < 3) {
updateConfig2To3();
}
if (version < 4) {
updateConfig3To4();
}
new BukkitRunnable() {
@Override
public void run() {
plugin.saveConfig();
plugin.getLogger().info("Configuration update complete!");
}
}.runTaskLater(plugin, 1L); // Run on 1 tick delay; on older versions Bukkit's scheduler is not guaranteed FIFO
} }
}.runTaskAsynchronously(plugin); if (version < 3) {
updateConfig2To3();
}
if (version < 4) {
updateConfig3To4();
}
plugin.getServer().getScheduler().runTask(plugin, () -> {
plugin.saveConfig();
plugin.getLogger().info("Configuration update complete!");
});
});
} }
private void updateConfig3To4() { private void updateConfig3To4() {
new BukkitRunnable() { plugin.getServer().getScheduler().runTask(plugin, () -> {
@Override plugin.getConfig().set("notify", null);
public void run() { plugin.getConfig().set("settings.locale", "en_US");
plugin.getConfig().set("notify", null); plugin.getConfig().set("config-version", 4);
plugin.getConfig().set("settings.locale", "en_US"); });
plugin.getConfig().set("config-version", 4);
}
}.runTask(plugin);
} }
private void updateConfig2To3() { private void updateConfig2To3() {
new BukkitRunnable() { plugin.getServer().getScheduler().runTask(plugin, () -> {
@Override plugin.getConfig().set("config-version", 3);
public void run() { plugin.getConfig().set("items.open-inv", null);
plugin.getConfig().set("config-version", 3); plugin.getConfig().set("ItemOpenInv", null);
plugin.getConfig().set("items.open-inv", null); plugin.getConfig().set("toggles.items.open-inv", null);
plugin.getConfig().set("ItemOpenInv", null); plugin.getConfig().set("settings.disable-saving",
plugin.getConfig().set("toggles.items.open-inv", null); plugin.getConfig().getBoolean("DisableSaving", false));
plugin.getConfig().set("settings.disable-saving", plugin.getConfig().set("DisableSaving", null);
plugin.getConfig().getBoolean("DisableSaving", false)); });
plugin.getConfig().set("DisableSaving", null);
}
}.runTask(plugin);
} }
private void updateConfig1To2() { private void updateConfig1To2() {
new BukkitRunnable() { plugin.getServer().getScheduler().runTask(plugin, () -> {
@Override // Get the old config settings
public void run() { boolean notifySilentChest = plugin.getConfig().getBoolean("NotifySilentChest", true);
// Get the old config settings boolean notifyAnyChest = plugin.getConfig().getBoolean("NotifyAnyChest", true);
boolean notifySilentChest = plugin.getConfig().getBoolean("NotifySilentChest", true); plugin.getConfig().set("ItemOpenInvItemID", null);
boolean notifyAnyChest = plugin.getConfig().getBoolean("NotifyAnyChest", true); plugin.getConfig().set("NotifySilentChest", null);
plugin.getConfig().set("ItemOpenInvItemID", null); plugin.getConfig().set("NotifyAnyChest", null);
plugin.getConfig().set("NotifySilentChest", null); plugin.getConfig().set("config-version", 2);
plugin.getConfig().set("NotifyAnyChest", null); plugin.getConfig().set("notify.any-chest", notifyAnyChest);
plugin.getConfig().set("config-version", 2); plugin.getConfig().set("notify.silent-chest", notifySilentChest);
plugin.getConfig().set("notify.any-chest", notifyAnyChest); });
plugin.getConfig().set("notify.silent-chest", notifySilentChest);
}
}.runTask(plugin);
updateToggles("AnyChest", "toggles.any-chest"); updateToggles("AnyChest", "toggles.any-chest");
updateToggles("SilentChest", "toggles.silent-chest"); updateToggles("SilentChest", "toggles.silent-chest");
} }
private void updateToggles(final String sectionName, final String newSectionName) { private void updateToggles(final String sectionName, final String newSectionName) {
ConfigurationSection section = plugin.getConfig().getConfigurationSection(sectionName);
// Ensure section exists // Ensure section exists
if (!plugin.getConfig().isConfigurationSection(sectionName)) { if (section == null) {
return; return;
} }
ConfigurationSection section = plugin.getConfig().getConfigurationSection(sectionName);
Set<String> keys = section.getKeys(false); Set<String> keys = section.getKeys(false);
// Ensure section has content // Ensure section has content
if (keys == null || keys.isEmpty()) { if (keys.isEmpty()) {
return; return;
} }
@@ -143,25 +128,20 @@ public class ConfigUpdater {
} }
} }
new BukkitRunnable() { plugin.getServer().getScheduler().runTask(plugin, () -> {
@Override // Wipe old ConfigurationSection
public void run() { plugin.getConfig().set(sectionName, null);
// Wipe old ConfigurationSection
plugin.getConfig().set(sectionName, null);
// Prepare new ConfigurationSection // Prepare new ConfigurationSection
ConfigurationSection newSection; ConfigurationSection newSection = plugin.getConfig().getConfigurationSection(newSectionName);
if (plugin.getConfig().isConfigurationSection(newSectionName)) { if (newSection == null) {
newSection = plugin.getConfig().getConfigurationSection(newSectionName); newSection = plugin.getConfig().createSection(newSectionName);
} else {
newSection = plugin.getConfig().createSection(newSectionName);
}
// Set new values
for (Map.Entry<String, Boolean> entry : toggles.entrySet()) {
newSection.set(entry.getKey(), entry.getValue());
}
} }
}.runTask(plugin); // Set new values
for (Map.Entry<String, Boolean> entry : toggles.entrySet()) {
newSection.set(entry.getKey(), entry.getValue());
}
});
} }
} }

View File

@@ -40,7 +40,6 @@ public class InternalAccessor {
this.version = packageName.substring(packageName.lastIndexOf('.') + 1); this.version = packageName.substring(packageName.lastIndexOf('.') + 1);
try { try {
// TODO: implement support for CraftMagicNumbers#getMappingsVersion
Class.forName("com.lishid.openinv.internal." + this.version + ".SpecialPlayerInventory"); Class.forName("com.lishid.openinv.internal." + this.version + ".SpecialPlayerInventory");
Class.forName("com.lishid.openinv.internal." + this.version + ".SpecialEnderChest"); Class.forName("com.lishid.openinv.internal." + this.version + ".SpecialEnderChest");
this.playerDataManager = this.createObject(IPlayerDataManager.class, "PlayerDataManager"); this.playerDataManager = this.createObject(IPlayerDataManager.class, "PlayerDataManager");

View File

@@ -41,7 +41,7 @@ public class LanguageManager {
private final OpenInv plugin; private final OpenInv plugin;
private final String defaultLocale; private final String defaultLocale;
private Map<String, YamlConfiguration> locales; private final Map<String, YamlConfiguration> locales;
public LanguageManager(@NotNull OpenInv plugin, @NotNull String defaultLocale) { public LanguageManager(@NotNull OpenInv plugin, @NotNull String defaultLocale) {
this.plugin = plugin; this.plugin = plugin;

View File

@@ -25,9 +25,9 @@ public enum Permissions {
EXEMPT("exempt"), EXEMPT("exempt"),
CROSSWORLD("crossworld"), CROSSWORLD("crossworld"),
SILENT("silent"), SILENT("silent"),
SILENT_DEFAULT("silent.default"), SILENT_DEFAULT("silent.default", true),
ANYCHEST("anychest"), ANYCHEST("anychest"),
ANY_DEFAULT("any.default"), ANY_DEFAULT("any.default", true),
ENDERCHEST("openender"), ENDERCHEST("openender"),
ENDERCHEST_ALL("openenderall"), ENDERCHEST_ALL("openenderall"),
SEARCH("search"), SEARCH("search"),
@@ -35,18 +35,25 @@ public enum Permissions {
EDITENDER("editender"), EDITENDER("editender"),
OPENSELF("openself"), OPENSELF("openself"),
OPENONLINE("openonline"), OPENONLINE("openonline"),
OPENOFFLINE("openoffline"); OPENOFFLINE("openoffline"),
SPECTATE("spectate");
private final String permission; private final String permission;
private final boolean uninheritable;
Permissions(String permission) { Permissions(String permission) {
this(permission, false);
}
Permissions(String permission, boolean uninheritable) {
this.permission = "OpenInv." + permission; this.permission = "OpenInv." + permission;
this.uninheritable = uninheritable;
} }
public boolean hasPermission(Permissible permissible) { public boolean hasPermission(Permissible permissible) {
boolean hasPermission = permissible.hasPermission(permission); boolean hasPermission = permissible.hasPermission(permission);
if (hasPermission || permissible.isPermissionSet(permission)) { if (uninheritable || hasPermission || permissible.isPermissionSet(permission)) {
return hasPermission; return hasPermission;
} }

View File

@@ -0,0 +1,30 @@
messages:
error:
consoleUnsupported: 'Du kannst diesen Befehl nicht von der Konsole ausführen.'
lootNotGenerated: '&cBeute noch nicht erstellt! Bitte schalte &b/silentcontainer&c aus.'
invalidMaterial: '&cUngültiges Material: "%target%"'
invalidNumber: '&cUngültige Nummer: "%target%"'
invalidPlayer: '&cSpieler nicht gefunden.'
permissionOpenSelf: '&cDu darfst dein eigenes Inventar nicht öffnen.'
permissionEnderAll: '&cDu darfst die Endertruhen von anderen Spielern nicht öffnen.'
permissionExempt: '&c%target%''s Inventar ist geschützt.'
permissionCrossWorld: '&c%target% ist nicht in der selben Welt wie du.'
permissionPlayerOnline: '&cDu darfst keine Inventare von Spielern öffnen, die online sind.'
permissionPlayerOffline: '&cDu darfst keine Inventare von Spielern öffnen, die offline sind.'
commandException: '&cAn error occurred. Please check console for details.'
info:
containerBlocked: 'Du öffnest einen gesperrten Container.'
containerBlockedSilent: 'Du öffnest einen gesperrten Container lautlos.'
containerSilent: 'Du öffnest einen Container lautlos.'
settingState: '%setting%: %state%'
player:
noMatches: 'Keine Spieler mit %target% gefunden.'
matches: 'Spieler hält %target%: %detail%'
container:
noMatches: 'Keine Container mit %target% gefunden.'
matches: 'Container hat %target%: %detail%'
on: 'an'
off: 'aus'
container:
player: '%player%''s Inventar'
enderchest: '%player%''s Endertruhe'

View File

@@ -0,0 +1,31 @@
messages:
error:
consoleUnsupported: 'No puedes usar este comando desde la consola.'
lootNotGenerated: '&c¡Botín no generado! Desactiva &b/silentcontainer&c.'
invalidMaterial: '&cMaterial no válido: "%target%"'
invalidNumber: '&cNúmero no válido: "%target%"'
invalidPlayer: '&cJugador no encontrado'
permissionOpenSelf: '&cNo tienes permisos para abrir tu inventario de esa forma.'
permissionEnderAll: '&cNo tienes permiso para abrir cofres de ender de otros jugadores.'
permissionExempt: '&c El inventario de %target% está protegido.'
permissionCrossWorld: '&c%target% no está en tu dimensión.'
permissionPlayerOnline: '&cNo estás autorizado para abrir inventarios de jugadores conectados.'
permissionPlayerOffline: '&cNo estás autorizado para abrir inventarios de jugadores desconectados.'
commandException: '&cSe ha producido un error, lee la consola para mas información.'
info:
containerBlocked: 'Estás abriendo un contenedor protegido.'
containerBlockedSilent: 'Estás abriendo sigilosamente un contenedor protegido.'
containerSilent: 'Estás abriendo un contenedor sigilosamente.'
settingState: '%setting%: %state%'
player:
noMatches: 'No se encontraron jugadores con %target%.'
matches: 'Jugadores con %target%: %detail%'
container:
noMatches: 'No se encontraron contenedores con %target%.'
matches: 'Contenedores con %target%: %detail%'
on: 'activado'
off: 'desactivado'
container:
player: 'Inventario de %player%'
enderchest: 'Cofre de Ender de %player%'

View File

@@ -5,7 +5,7 @@ author: lishid
authors: [Jikoo, ShadowRanger] authors: [Jikoo, ShadowRanger]
description: > description: >
This plugin allows you to open a player's inventory as a chest and interact with it in real time. This plugin allows you to open a player's inventory as a chest and interact with it in real time.
api-version: "1.14" api-version: "1.15"
permissions: permissions:
OpenInv.any.default: OpenInv.any.default:
@@ -27,6 +27,7 @@ permissions:
OpenInv.searchcontainer: true OpenInv.searchcontainer: true
OpenInv.openonline: true OpenInv.openonline: true
OpenInv.openoffline: true OpenInv.openoffline: true
OpenInv.spectate: true
OpenInv.openinv: OpenInv.openinv:
default: op default: op
children: children:

22
pom.xml
View File

@@ -21,7 +21,7 @@
<artifactId>openinvparent</artifactId> <artifactId>openinvparent</artifactId>
<name>OpenInvParent</name> <name>OpenInvParent</name>
<url>http://dev.bukkit.org/bukkit-plugins/openinv/</url> <url>http://dev.bukkit.org/bukkit-plugins/openinv/</url>
<version>4.1.2-SNAPSHOT</version> <version>4.1.6-SNAPSHOT</version>
<packaging>pom</packaging> <packaging>pom</packaging>
@@ -54,26 +54,6 @@
</activation> </activation>
</profile> </profile>
<profile>
<id>latest</id>
<activation>
<property>
<name>latest</name>
<value>true</value>
</property>
</activation>
</profile>
<profile>
<id>recent</id>
<activation>
<property>
<name>recent</name>
<value>true</value>
</property>
</activation>
</profile>
</profiles> </profiles>
<repositories> <repositories>