diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6489274..a73e107 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -9,8 +9,6 @@ on:
jobs:
build:
runs-on: ubuntu-latest
- strategy:
- fail-fast: true
steps:
- name: Checkout Code
uses: actions/checkout@v2
@@ -28,18 +26,10 @@ jobs:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
- # If the cache was not present, run BuildTools to install the relevant versions to Maven.
- # This will take approximately forever.
+ # Install Spigot dependencies.
+ # This script uses Maven to check all required installations and ensure that they are present.
- name: Install Spigot Dependencies
- if: steps.cache.outputs.cache-hit != 'true'
- run: |
- mkdir ~/buildtools
- cd ~/buildtools
- wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar
- java -jar BuildTools.jar --rev 1.8.8
- java -jar BuildTools.jar --rev 1.15.2
- java -jar BuildTools.jar --rev 1.16.3
- java -jar BuildTools.jar --rev 1.16.4
+ run: . scripts/install_spigot_dependencies.sh
- name: Build With Maven
run: mvn -e clean package -am -P all
@@ -70,6 +60,9 @@ jobs:
- name: Download Artifacts
uses: actions/download-artifact@v2
+ - name: Generate changelog
+ run: . scripts/generate_changelog.sh
+
- name: Create Release
id: create-release
uses: actions/create-release@v1
@@ -78,6 +71,7 @@ jobs:
with:
tag_name: ${{ github.ref }}
release_name: Release ${{ github.ref }}
+ body: ${{ env.GENERATED_CHANGELOG }}
draft: true
prerelease: false
diff --git a/api/pom.xml b/api/pom.xml
index d42d670..914071c 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -36,7 +36,7 @@
org.spigotmcspigot-api
- 1.8.8-R0.1-SNAPSHOT
+ 1.16.5-R0.1-SNAPSHOTprovided
diff --git a/internal/pom.xml b/internal/pom.xml
index 770345b..2bbd718 100644
--- a/internal/pom.xml
+++ b/internal/pom.xml
@@ -33,9 +33,6 @@
all
- v1_8_R3
- v1_15_R1
- v1_16_R2v1_16_R3
diff --git a/internal/v1_15_R1/pom.xml b/internal/v1_15_R1/pom.xml
deleted file mode 100644
index 021a5ce..0000000
--- a/internal/v1_15_R1/pom.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
- 4.0.0
-
-
- com.lishid
- openinvinternal
- 4.1.5-TF
-
-
- openinvadapter1_15_R1
- OpenInvAdapter1_15_R1
-
-
-
- org.spigotmc
- spigot
- 1.15.2-R0.1-SNAPSHOT
- provided
-
-
- com.lishid
- openinvplugincore
- 4.1.5-TF
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-shade-plugin
- 3.2.2
-
- true
-
-
-
- package
-
- shade
-
-
-
-
-
-
- maven-compiler-plugin
- 3.8.1
-
-
- 1.8
-
-
-
-
-
-
\ No newline at end of file
diff --git a/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/AnySilentContainer.java b/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/AnySilentContainer.java
deleted file mode 100644
index 3cceef7..0000000
--- a/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/AnySilentContainer.java
+++ /dev/null
@@ -1,359 +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 .
- */
-
-package com.lishid.openinv.internal.v1_15_R1;
-
-import com.lishid.openinv.OpenInv;
-import com.lishid.openinv.internal.IAnySilentContainer;
-import java.lang.reflect.Field;
-import net.minecraft.server.v1_15_R1.Block;
-import net.minecraft.server.v1_15_R1.BlockBarrel;
-import net.minecraft.server.v1_15_R1.BlockChest;
-import net.minecraft.server.v1_15_R1.BlockChestTrapped;
-import net.minecraft.server.v1_15_R1.BlockEnderChest;
-import net.minecraft.server.v1_15_R1.BlockPosition;
-import net.minecraft.server.v1_15_R1.BlockPropertyChestType;
-import net.minecraft.server.v1_15_R1.BlockShulkerBox;
-import net.minecraft.server.v1_15_R1.ChatMessage;
-import net.minecraft.server.v1_15_R1.Container;
-import net.minecraft.server.v1_15_R1.ContainerChest;
-import net.minecraft.server.v1_15_R1.Containers;
-import net.minecraft.server.v1_15_R1.EntityHuman;
-import net.minecraft.server.v1_15_R1.EntityPlayer;
-import net.minecraft.server.v1_15_R1.EnumGamemode;
-import net.minecraft.server.v1_15_R1.IBlockData;
-import net.minecraft.server.v1_15_R1.IChatBaseComponent;
-import net.minecraft.server.v1_15_R1.ITileInventory;
-import net.minecraft.server.v1_15_R1.InventoryEnderChest;
-import net.minecraft.server.v1_15_R1.InventoryLargeChest;
-import net.minecraft.server.v1_15_R1.PlayerInteractManager;
-import net.minecraft.server.v1_15_R1.PlayerInventory;
-import net.minecraft.server.v1_15_R1.TileEntity;
-import net.minecraft.server.v1_15_R1.TileEntityChest;
-import net.minecraft.server.v1_15_R1.TileEntityEnderChest;
-import net.minecraft.server.v1_15_R1.TileEntityLootable;
-import net.minecraft.server.v1_15_R1.TileInventory;
-import net.minecraft.server.v1_15_R1.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);
- }, BlockEnderChest.e));
- 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.i(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();
- }
- }
-
-}
diff --git a/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/PlayerDataManager.java b/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/PlayerDataManager.java
deleted file mode 100644
index 23876cf..0000000
--- a/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/PlayerDataManager.java
+++ /dev/null
@@ -1,289 +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 .
- */
-
-package com.lishid.openinv.internal.v1_15_R1;
-
-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_15_R1.ChatComponentText;
-import net.minecraft.server.v1_15_R1.ChatMessageType;
-import net.minecraft.server.v1_15_R1.Container;
-import net.minecraft.server.v1_15_R1.Containers;
-import net.minecraft.server.v1_15_R1.DimensionManager;
-import net.minecraft.server.v1_15_R1.Entity;
-import net.minecraft.server.v1_15_R1.EntityHuman;
-import net.minecraft.server.v1_15_R1.EntityPlayer;
-import net.minecraft.server.v1_15_R1.MinecraftServer;
-import net.minecraft.server.v1_15_R1.NBTCompressedStreamTools;
-import net.minecraft.server.v1_15_R1.NBTTagCompound;
-import net.minecraft.server.v1_15_R1.PacketPlayOutChat;
-import net.minecraft.server.v1_15_R1.PacketPlayOutOpenWindow;
-import net.minecraft.server.v1_15_R1.PlayerInteractManager;
-import net.minecraft.server.v1_15_R1.PlayerInventory;
-import net.minecraft.server.v1_15_R1.WorldNBTStorage;
-import org.apache.logging.log4j.LogManager;
-import org.bukkit.Bukkit;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.Server;
-import org.bukkit.craftbukkit.v1_15_R1.CraftServer;
-import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
-import org.bukkit.craftbukkit.v1_15_R1.event.CraftEventFactory;
-import org.bukkit.craftbukkit.v1_15_R1.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 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();
- EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(DimensionManager.OVERWORLD), profile,
- new PlayerInteractManager(server.getWorldServer(DimensionManager.OVERWORLD)));
-
- 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 = (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);
- } 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));
- }
- }
-
-}
diff --git a/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/SpecialEnderChest.java b/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/SpecialEnderChest.java
deleted file mode 100644
index de70b04..0000000
--- a/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/SpecialEnderChest.java
+++ /dev/null
@@ -1,256 +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 .
- */
-
-package com.lishid.openinv.internal.v1_15_R1;
-
-import com.lishid.openinv.internal.ISpecialEnderChest;
-import java.util.List;
-import net.minecraft.server.v1_15_R1.AutoRecipeStackManager;
-import net.minecraft.server.v1_15_R1.ContainerUtil;
-import net.minecraft.server.v1_15_R1.EntityHuman;
-import net.minecraft.server.v1_15_R1.EntityPlayer;
-import net.minecraft.server.v1_15_R1.IInventoryListener;
-import net.minecraft.server.v1_15_R1.InventoryEnderChest;
-import net.minecraft.server.v1_15_R1.ItemStack;
-import net.minecraft.server.v1_15_R1.NonNullList;
-import org.bukkit.Location;
-import org.bukkit.craftbukkit.v1_15_R1.entity.CraftHumanEntity;
-import org.bukkit.craftbukkit.v1_15_R1.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 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 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 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.a;
- }
-
- @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.a;
- }
-
- 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.a;
- }
- }
- }
- }
-
- 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.a;
- } else {
- this.items.set(i, ItemStack.a);
- 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);
- }
-
- }
-
-}
diff --git a/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/SpecialPlayerInventory.java b/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/SpecialPlayerInventory.java
deleted file mode 100644
index ff59d3c..0000000
--- a/internal/v1_15_R1/src/main/java/com/lishid/openinv/internal/v1_15_R1/SpecialPlayerInventory.java
+++ /dev/null
@@ -1,757 +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 .
- */
-
-package com.lishid.openinv.internal.v1_15_R1;
-
-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_15_R1.AutoRecipeStackManager;
-import net.minecraft.server.v1_15_R1.ChatMessage;
-import net.minecraft.server.v1_15_R1.ContainerUtil;
-import net.minecraft.server.v1_15_R1.CrashReport;
-import net.minecraft.server.v1_15_R1.CrashReportSystemDetails;
-import net.minecraft.server.v1_15_R1.EntityHuman;
-import net.minecraft.server.v1_15_R1.EntityPlayer;
-import net.minecraft.server.v1_15_R1.EnumItemSlot;
-import net.minecraft.server.v1_15_R1.IBlockData;
-import net.minecraft.server.v1_15_R1.IChatBaseComponent;
-import net.minecraft.server.v1_15_R1.Item;
-import net.minecraft.server.v1_15_R1.ItemArmor;
-import net.minecraft.server.v1_15_R1.ItemStack;
-import net.minecraft.server.v1_15_R1.NBTTagCompound;
-import net.minecraft.server.v1_15_R1.NBTTagList;
-import net.minecraft.server.v1_15_R1.NonNullList;
-import net.minecraft.server.v1_15_R1.PacketPlayOutSetSlot;
-import net.minecraft.server.v1_15_R1.PlayerInventory;
-import net.minecraft.server.v1_15_R1.ReportedException;
-import net.minecraft.server.v1_15_R1.World;
-import org.bukkit.Location;
-import org.bukkit.craftbukkit.v1_15_R1.entity.CraftHumanEntity;
-import org.bukkit.craftbukkit.v1_15_R1.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 items, armor, extraSlots;
- private List> 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 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.a;
- }
-
- return list.get(i);
- }
-
- private ItemStack getRawItem(int i) {
- NonNullList list = null;
- for (NonNullList next : this.f) {
- if (i < next.size()) {
- list = next;
- break;
- }
- i -= next.size();
- }
-
- return list == null ? ItemStack.a : 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 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 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.a;
- }
-
- return list.get(i).isEmpty() ? ItemStack.a : ContainerUtil.a(list, i, j);
- }
-
- @Override
- public ItemStack splitWithoutUpdate(int i) {
- List 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.a;
- }
-
- if (!list.get(i).isEmpty()) {
- ItemStack itemstack = list.get(i);
-
- list.set(i, ItemStack.a);
- return itemstack;
- }
-
- return ItemStack.a;
- }
-
- @Override
- public List getContents() {
- return this.f.stream().flatMap(List::stream).collect(Collectors.toList());
- }
-
- @Override
- public List 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 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.a;
- }
-
- private boolean a(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.a(itemstack, itemstack1)) {
- remains -= Math.min(itemstack1.getMaxStackSize(), this.getMaxStackSize()) - itemstack1.getCount();
- }
-
- if (remains <= 0) {
- return itemstack.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 predicate, int i) {
- int j = 0;
-
- int k;
- for (k = 0; k < this.getSize(); ++k) {
- ItemStack itemstack = this.getItem(k);
- if (!itemstack.isEmpty() && predicate.test(itemstack)) {
- int l = i <= 0 ? itemstack.getCount() : Math.min(i - j, itemstack.getCount());
- 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;
- }
-
- 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);
- if (itemstack.hasTag()) {
- itemstack1.setTag(itemstack.getTag().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.a(this.getItem(this.itemInHandIndex), itemstack)) {
- return this.itemInHandIndex;
- } else if (this.a(this.getItem(40), itemstack)) {
- return 40;
- } else {
- for (int i = 0; i < this.items.size(); ++i) {
- if (this.a(this.items.get(i), itemstack)) {
- return i;
- }
- }
-
- return -1;
- }
- }
-
- @Override
- public void j() {
-
- for (List 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 list : this.f) {
- for (int i = 0; i < list.size(); ++i) {
- if (list.get(i) == itemstack) {
- list.set(i, ItemStack.a);
- 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 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 boolean b(IBlockData iblockdata) {
- return this.getItem(this.itemInHandIndex).canDestroySpecialBlock(iblockdata);
- }
-
- @Override
- public void a(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 (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 itemStacks : this.f) {
- for (int i = 0; i < itemStacks.size(); ++i) {
- ItemStack itemstack = itemStacks.get(i);
- if (!itemstack.isEmpty()) {
- itemStacks.set(i, ItemStack.a);
- 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);
- }
- }
-
-}
diff --git a/internal/v1_16_R2/pom.xml b/internal/v1_16_R2/pom.xml
deleted file mode 100644
index ef365b0..0000000
--- a/internal/v1_16_R2/pom.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-
-
-
-
- 4.0.0
-
-
- com.lishid
- openinvinternal
- 4.1.5-TF
-
-
- openinvadapter1_16_R2
- OpenInvAdapter1_16_R2
-
-
-
- org.spigotmc
- spigot
- 1.16.3-R0.1-SNAPSHOT
- provided
-
-
- com.lishid
- openinvplugincore
- 4.1.5-TF
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-shade-plugin
- 3.2.2
-
- true
-
-
-
- package
-
- shade
-
-
-
-
-
-
- maven-compiler-plugin
- 3.8.1
-
-
- 1.8
-
-
-
-
-
-
\ No newline at end of file
diff --git a/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/AnySilentContainer.java b/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/AnySilentContainer.java
deleted file mode 100644
index 4040449..0000000
--- a/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/AnySilentContainer.java
+++ /dev/null
@@ -1,358 +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 .
- */
-
-package com.lishid.openinv.internal.v1_16_R2;
-
-import com.lishid.openinv.OpenInv;
-import com.lishid.openinv.internal.IAnySilentContainer;
-import java.lang.reflect.Field;
-import net.minecraft.server.v1_16_R2.Block;
-import net.minecraft.server.v1_16_R2.BlockBarrel;
-import net.minecraft.server.v1_16_R2.BlockChest;
-import net.minecraft.server.v1_16_R2.BlockChestTrapped;
-import net.minecraft.server.v1_16_R2.BlockPosition;
-import net.minecraft.server.v1_16_R2.BlockPropertyChestType;
-import net.minecraft.server.v1_16_R2.BlockShulkerBox;
-import net.minecraft.server.v1_16_R2.ChatMessage;
-import net.minecraft.server.v1_16_R2.Container;
-import net.minecraft.server.v1_16_R2.ContainerChest;
-import net.minecraft.server.v1_16_R2.Containers;
-import net.minecraft.server.v1_16_R2.EntityHuman;
-import net.minecraft.server.v1_16_R2.EntityPlayer;
-import net.minecraft.server.v1_16_R2.EnumGamemode;
-import net.minecraft.server.v1_16_R2.IBlockData;
-import net.minecraft.server.v1_16_R2.IChatBaseComponent;
-import net.minecraft.server.v1_16_R2.ITileInventory;
-import net.minecraft.server.v1_16_R2.InventoryEnderChest;
-import net.minecraft.server.v1_16_R2.InventoryLargeChest;
-import net.minecraft.server.v1_16_R2.PlayerInteractManager;
-import net.minecraft.server.v1_16_R2.PlayerInventory;
-import net.minecraft.server.v1_16_R2.TileEntity;
-import net.minecraft.server.v1_16_R2.TileEntityChest;
-import net.minecraft.server.v1_16_R2.TileEntityEnderChest;
-import net.minecraft.server.v1_16_R2.TileEntityLootable;
-import net.minecraft.server.v1_16_R2.TileInventory;
-import net.minecraft.server.v1_16_R2.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();
- }
- }
-
-}
diff --git a/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/PlayerDataManager.java b/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/PlayerDataManager.java
deleted file mode 100644
index 79a0743..0000000
--- a/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/PlayerDataManager.java
+++ /dev/null
@@ -1,295 +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 .
- */
-
-package com.lishid.openinv.internal.v1_16_R2;
-
-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_R2.ChatComponentText;
-import net.minecraft.server.v1_16_R2.ChatMessageType;
-import net.minecraft.server.v1_16_R2.Container;
-import net.minecraft.server.v1_16_R2.Containers;
-import net.minecraft.server.v1_16_R2.Entity;
-import net.minecraft.server.v1_16_R2.EntityHuman;
-import net.minecraft.server.v1_16_R2.EntityPlayer;
-import net.minecraft.server.v1_16_R2.MinecraftServer;
-import net.minecraft.server.v1_16_R2.NBTCompressedStreamTools;
-import net.minecraft.server.v1_16_R2.NBTTagCompound;
-import net.minecraft.server.v1_16_R2.PacketPlayOutChat;
-import net.minecraft.server.v1_16_R2.PacketPlayOutOpenWindow;
-import net.minecraft.server.v1_16_R2.PlayerInteractManager;
-import net.minecraft.server.v1_16_R2.PlayerInventory;
-import net.minecraft.server.v1_16_R2.SystemUtils;
-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.bukkit.Bukkit;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.Server;
-import org.bukkit.craftbukkit.v1_16_R2.CraftServer;
-import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
-import org.bukkit.craftbukkit.v1_16_R2.event.CraftEventFactory;
-import org.bukkit.craftbukkit.v1_16_R2.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));
- }
- }
-
-}
diff --git a/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/SpecialEnderChest.java b/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/SpecialEnderChest.java
deleted file mode 100644
index f2dc5f6..0000000
--- a/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/SpecialEnderChest.java
+++ /dev/null
@@ -1,256 +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 .
- */
-
-package com.lishid.openinv.internal.v1_16_R2;
-
-import com.lishid.openinv.internal.ISpecialEnderChest;
-import java.util.List;
-import net.minecraft.server.v1_16_R2.AutoRecipeStackManager;
-import net.minecraft.server.v1_16_R2.ContainerUtil;
-import net.minecraft.server.v1_16_R2.EntityHuman;
-import net.minecraft.server.v1_16_R2.EntityPlayer;
-import net.minecraft.server.v1_16_R2.IInventoryListener;
-import net.minecraft.server.v1_16_R2.InventoryEnderChest;
-import net.minecraft.server.v1_16_R2.ItemStack;
-import net.minecraft.server.v1_16_R2.NonNullList;
-import org.bukkit.Location;
-import org.bukkit.craftbukkit.v1_16_R2.entity.CraftHumanEntity;
-import org.bukkit.craftbukkit.v1_16_R2.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 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 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 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);
- }
-
- }
-
-}
diff --git a/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/SpecialPlayerInventory.java b/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/SpecialPlayerInventory.java
deleted file mode 100644
index e1b22cf..0000000
--- a/internal/v1_16_R2/src/main/java/com/lishid/openinv/internal/v1_16_R2/SpecialPlayerInventory.java
+++ /dev/null
@@ -1,733 +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 .
- */
-
-package com.lishid.openinv.internal.v1_16_R2;
-
-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_R2.AutoRecipeStackManager;
-import net.minecraft.server.v1_16_R2.ChatMessage;
-import net.minecraft.server.v1_16_R2.ContainerUtil;
-import net.minecraft.server.v1_16_R2.CrashReport;
-import net.minecraft.server.v1_16_R2.CrashReportSystemDetails;
-import net.minecraft.server.v1_16_R2.DamageSource;
-import net.minecraft.server.v1_16_R2.EntityHuman;
-import net.minecraft.server.v1_16_R2.EntityPlayer;
-import net.minecraft.server.v1_16_R2.EnumItemSlot;
-import net.minecraft.server.v1_16_R2.IBlockData;
-import net.minecraft.server.v1_16_R2.IChatBaseComponent;
-import net.minecraft.server.v1_16_R2.IInventory;
-import net.minecraft.server.v1_16_R2.Item;
-import net.minecraft.server.v1_16_R2.ItemArmor;
-import net.minecraft.server.v1_16_R2.ItemStack;
-import net.minecraft.server.v1_16_R2.NBTTagCompound;
-import net.minecraft.server.v1_16_R2.NBTTagList;
-import net.minecraft.server.v1_16_R2.NonNullList;
-import net.minecraft.server.v1_16_R2.PacketPlayOutSetSlot;
-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.craftbukkit.v1_16_R2.entity.CraftHumanEntity;
-import org.bukkit.craftbukkit.v1_16_R2.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 items, armor, extraSlots;
- private List> 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 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 list = null;
- for (NonNullList 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 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 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 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 getContents() {
- return this.f.stream().flatMap(List::stream).collect(Collectors.toList());
- }
-
- @Override
- public List 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 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 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 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 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 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 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);
- }
- }
-
-}
diff --git a/internal/v1_16_R3/pom.xml b/internal/v1_16_R3/pom.xml
index 7ead3e9..4b9fa78 100644
--- a/internal/v1_16_R3/pom.xml
+++ b/internal/v1_16_R3/pom.xml
@@ -32,7 +32,7 @@
org.spigotmcspigot
- 1.16.4-R0.1-SNAPSHOT
+ 1.16.5-R0.1-SNAPSHOTprovided
diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java
index e6a2083..5d78617 100644
--- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java
+++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/AnySilentContainer.java
@@ -190,29 +190,8 @@ public class AnySilentContainer implements IAnySilentContainer {
InventoryEnderChest enderChest = player.getEnderChest();
enderChest.a((TileEntityEnderChest) tile);
player.openContainer(new TileInventory((containerCounter, playerInventory, ignored) -> {
- Containers> containers;
+ Containers> containers = PlayerDataManager.getContainers(enderChest.getSize());
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);
@@ -262,6 +241,12 @@ public class AnySilentContainer implements IAnySilentContainer {
}
public IChatBaseComponent getScoreboardDisplayName() {
+ if (leftChest.hasCustomName()) {
+ return leftChest.getScoreboardDisplayName();
+ }
+ if (rightChest.hasCustomName()) {
+ return rightChest.getScoreboardDisplayName();
+ }
return new ChatMessage("container.chestDouble");
}
};
diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java
new file mode 100644
index 0000000..def3f96
--- /dev/null
+++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/OpenPlayer.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2011-2021 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 .
+ */
+
+package com.lishid.openinv.internal.v1_16_R3;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import net.minecraft.server.v1_16_R3.EntityPlayer;
+import net.minecraft.server.v1_16_R3.NBTCompressedStreamTools;
+import net.minecraft.server.v1_16_R3.NBTTagCompound;
+import net.minecraft.server.v1_16_R3.WorldNBTStorage;
+import org.apache.logging.log4j.LogManager;
+import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
+import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
+
+public class OpenPlayer extends CraftPlayer {
+
+ public OpenPlayer(CraftServer server, EntityPlayer entity) {
+ super(server, entity);
+ }
+
+ @Override
+ public void saveData() {
+ super.saveData();
+ EntityPlayer player = this.getHandle();
+ // 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());
+ }
+ }
+
+}
diff --git a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java
index e0737c5..5a29ceb 100644
--- a/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java
+++ b/internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java
@@ -16,32 +16,21 @@
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.lishid.openinv.internal.OpenInventoryView;
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;
@@ -49,10 +38,7 @@ 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;
@@ -136,40 +122,7 @@ public class PlayerDataManager implements IPlayerDataManager {
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());
- }
- }
- });
+ bukkitEntity.set(player, new OpenPlayer(player.server.server, player));
}
@NotNull
@@ -195,68 +148,20 @@ public class PlayerDataManager implements IPlayerDataManager {
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 {
+ InventoryView view = getView(player, inventory);
+
+ if (view == null) {
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()) {
+ Container container = new CraftContainer(view, 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;
- }
+ return getContainers(inventory.getBukkitInventory().getSize());
}
};
- container.setTitle(new ChatComponentText(title));
+ container.setTitle(new ChatComponentText(view.getTitle()));
container = CraftEventFactory.callInventoryOpenEvent(nmsPlayer, container);
if (container == null) {
@@ -272,24 +177,61 @@ public class PlayerDataManager implements IPlayerDataManager {
}
- @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));
+ private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) {
+ if (inventory instanceof SpecialEnderChest) {
+ return new OpenInventoryView(player, inventory, "container.enderchest", "'s Ender Chest");
+ } else if (inventory instanceof SpecialPlayerInventory) {
+ return new OpenInventoryView(player, inventory, "container.player", "'s Inventory");
+ } else {
+ return null;
}
}
+ static @NotNull Containers> getContainers(int inventorySize) {
+ switch (inventorySize) {
+ case 9:
+ return Containers.GENERIC_9X1;
+ case 18:
+ return Containers.GENERIC_9X2;
+ case 36:
+ return Containers.GENERIC_9X4;
+ case 41: // PLAYER
+ case 45:
+ return Containers.GENERIC_9X5;
+ case 54:
+ return Containers.GENERIC_9X6;
+ case 27:
+ default:
+ return Containers.GENERIC_9X3;
+ }
+ }
+
+ @Override
+ public int convertToPlayerSlot(InventoryView view, int rawSlot) {
+ int topSize = view.getTopInventory().getSize();
+ if (topSize <= rawSlot) {
+ // Slot is not inside special inventory, use Bukkit logic.
+ return view.convertSlot(rawSlot);
+ }
+
+ // Main inventory, slots 0-26 -> 9-35
+ if (rawSlot < 27) {
+ return rawSlot + 9;
+ }
+ // Hotbar, slots 27-35 -> 0-8
+ if (rawSlot < 36) {
+ return rawSlot - 27;
+ }
+ // Armor, slots 36-39 -> 39-36
+ if (rawSlot < 40) {
+ return 36 + (39 - rawSlot);
+ }
+ // Off hand
+ if (rawSlot == 40) {
+ return 40;
+ }
+ // Drop slots, "out of inventory"
+ return -1;
+ }
+
}
diff --git a/internal/v1_8_R3/pom.xml b/internal/v1_8_R3/pom.xml
deleted file mode 100644
index b5951a8..0000000
--- a/internal/v1_8_R3/pom.xml
+++ /dev/null
@@ -1,74 +0,0 @@
-
-
-
- 4.0.0
-
-
- com.lishid
- openinvinternal
- 4.1.5-TF
-
-
- openinvadapter1_8_R3
- OpenInvAdapter1_8_R3
-
-
-
- org.spigotmc
- spigot
- 1.8.8-R0.1-SNAPSHOT
- provided
-
-
- com.lishid
- openinvplugincore
- 4.1.5-TF
-
-
-
-
-
-
- org.apache.maven.plugins
- maven-shade-plugin
- 3.2.2
-
- true
-
-
-
- package
-
- shade
-
-
-
-
-
-
- maven-compiler-plugin
- 3.8.1
-
-
- 1.8
-
-
-
-
-
-
diff --git a/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/AnySilentContainer.java b/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/AnySilentContainer.java
deleted file mode 100644
index e671037..0000000
--- a/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/AnySilentContainer.java
+++ /dev/null
@@ -1,250 +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 .
- */
-
-package com.lishid.openinv.internal.v1_8_R3;
-
-import com.lishid.openinv.internal.IAnySilentContainer;
-import java.lang.reflect.Field;
-import net.minecraft.server.v1_8_R3.AxisAlignedBB;
-import net.minecraft.server.v1_8_R3.Block;
-import net.minecraft.server.v1_8_R3.BlockChest;
-import net.minecraft.server.v1_8_R3.BlockEnderChest;
-import net.minecraft.server.v1_8_R3.BlockPosition;
-import net.minecraft.server.v1_8_R3.Entity;
-import net.minecraft.server.v1_8_R3.EntityOcelot;
-import net.minecraft.server.v1_8_R3.EntityPlayer;
-import net.minecraft.server.v1_8_R3.EnumDirection;
-import net.minecraft.server.v1_8_R3.ITileInventory;
-import net.minecraft.server.v1_8_R3.InventoryEnderChest;
-import net.minecraft.server.v1_8_R3.InventoryLargeChest;
-import net.minecraft.server.v1_8_R3.PlayerInteractManager;
-import net.minecraft.server.v1_8_R3.StatisticList;
-import net.minecraft.server.v1_8_R3.TileEntity;
-import net.minecraft.server.v1_8_R3.TileEntityChest;
-import net.minecraft.server.v1_8_R3.TileEntityEnderChest;
-import net.minecraft.server.v1_8_R3.World;
-import net.minecraft.server.v1_8_R3.WorldSettings.EnumGamemode;
-import org.bukkit.Material;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.InventoryView;
-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 (Exception e) {
- System.err.println("[OpenInv] Unable to directly write player gamemode! SilentChest will fail.");
- e.printStackTrace();
- }
- }
-
- @Override
- public boolean isAnySilentContainer(@NotNull org.bukkit.block.Block bukkitBlock) {
- return bukkitBlock.getType() == Material.ENDER_CHEST || bukkitBlock.getState() instanceof org.bukkit.block.Chest;
- }
-
- @Override
- public boolean isAnyContainerNeeded(@NotNull Player bukkitPlayer, @NotNull org.bukkit.block.Block bukkitBlock) {
-
- World world = PlayerDataManager.getHandle(bukkitPlayer).world;
- BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());
- Block block = world.getType(blockPosition).getBlock();
-
- if (block instanceof BlockEnderChest) {
- // Ender chests are not blocked by ocelots.
- return world.getType(blockPosition.up()).getBlock().c();
- }
-
- // Check if chest is blocked or has an ocelot on top
- if (isBlockedChest(world, blockPosition)) {
- return true;
- }
-
- // Check for matching adjacent chests that are blocked or have an ocelot on top
- for (EnumDirection localEnumDirection : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
- BlockPosition localBlockPosition = blockPosition.shift(localEnumDirection);
- Block localBlock = world.getType(localBlockPosition).getBlock();
-
- if (localBlock != block) {
- continue;
- }
-
- TileEntity localTileEntity = world.getTileEntity(localBlockPosition);
- if (!(localTileEntity instanceof TileEntityChest)) {
- continue;
- }
-
- if (isBlockedChest(world, localBlockPosition)) {
- return true;
- }
- }
-
- return false;
- }
-
- private boolean isBlockedChest(World world, BlockPosition blockPosition) {
- // For reference, loot at net.minecraft.server.BlockChest
- return world.getType(blockPosition.up()).getBlock().c() || hasOcelotOnTop(world, blockPosition);
- }
-
- private boolean hasOcelotOnTop(World world, BlockPosition blockPosition) {
- for (Entity localEntity : world.a(EntityOcelot.class,
- new AxisAlignedBB(blockPosition.getX(), blockPosition.getY() + 1,
- blockPosition.getZ(), blockPosition.getX() + 1, blockPosition.getY() + 2,
- blockPosition.getZ() + 1))) {
- EntityOcelot localEntityOcelot = (EntityOcelot) localEntity;
- if (localEntityOcelot.isSitting()) {
- return true;
- }
- }
-
- return false;
- }
-
- @Override
- public boolean activateContainer(@NotNull Player bukkitPlayer, boolean silent, @NotNull org.bukkit.block.Block bukkitBlock) {
-
- EntityPlayer player = PlayerDataManager.getHandle(bukkitPlayer);
-
- // Silent ender chest is pretty much API-only
- if (silent && bukkitBlock.getType() == Material.ENDER_CHEST) {
- bukkitPlayer.openInventory(bukkitPlayer.getEnderChest());
- player.b(StatisticList.V);
- return true;
- }
-
- World world = player.world;
- BlockPosition blockPosition = new BlockPosition(bukkitBlock.getX(), bukkitBlock.getY(), bukkitBlock.getZ());
- Object 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(enderChest);
- player.b(StatisticList.V);
- return true;
- }
-
- if (!(tile instanceof ITileInventory)) {
- return false;
- }
-
- ITileInventory tileInventory = (ITileInventory) tile;
- Block block = world.getType(blockPosition).getBlock();
-
- if (block instanceof BlockChest) {
- for (EnumDirection localEnumDirection : EnumDirection.EnumDirectionLimit.HORIZONTAL) {
- BlockPosition localBlockPosition = blockPosition.shift(localEnumDirection);
- Block localBlock = world.getType(localBlockPosition).getBlock();
-
- if (localBlock != block) {
- continue;
- }
-
- TileEntity localTileEntity = world.getTileEntity(localBlockPosition);
- if (!(localTileEntity instanceof TileEntityChest)) {
- continue;
- }
-
- if ((localEnumDirection == EnumDirection.WEST) || (localEnumDirection == EnumDirection.NORTH)) {
- tileInventory = new InventoryLargeChest("container.chestDouble",
- (TileEntityChest) localTileEntity, tileInventory);
- } else {
- tileInventory = new InventoryLargeChest("container.chestDouble",
- tileInventory, (TileEntityChest) localTileEntity);
- }
- break;
- }
-
- BlockChest blockChest = (BlockChest) block;
- if (blockChest.b == 0) {
- player.b(StatisticList.aa);
- } else if (blockChest.b == 1) {
- player.b(StatisticList.U);
- }
- }
-
- // AnyChest only - SilentChest not active, container unsupported, or unnecessary.
- if (!silent || player.playerInteractManager.getGameMode() == EnumGamemode.SPECTATOR) {
- player.openContainer(tileInventory);
- return true;
- }
-
- // SilentChest requires access to setting players' gamemode directly.
- if (this.playerInteractManagerGamemode == null) {
- 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:
- 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 (Exception e) {
- e.printStackTrace();
- }
- }
-
-}
diff --git a/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/PlayerDataManager.java b/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/PlayerDataManager.java
deleted file mode 100644
index f38240d..0000000
--- a/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/PlayerDataManager.java
+++ /dev/null
@@ -1,201 +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 .
- */
-
-package com.lishid.openinv.internal.v1_8_R3;
-
-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_8_R3.ChatComponentText;
-import net.minecraft.server.v1_8_R3.Entity;
-import net.minecraft.server.v1_8_R3.EntityPlayer;
-import net.minecraft.server.v1_8_R3.MinecraftServer;
-import net.minecraft.server.v1_8_R3.NBTCompressedStreamTools;
-import net.minecraft.server.v1_8_R3.NBTTagCompound;
-import net.minecraft.server.v1_8_R3.PacketPlayOutChat;
-import net.minecraft.server.v1_8_R3.PlayerInteractManager;
-import net.minecraft.server.v1_8_R3.WorldNBTStorage;
-import org.apache.logging.log4j.LogManager;
-import org.bukkit.Bukkit;
-import org.bukkit.OfflinePlayer;
-import org.bukkit.Server;
-import org.bukkit.craftbukkit.v1_8_R3.CraftServer;
-import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.InventoryView;
-import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
-
-public class PlayerDataManager implements IPlayerDataManager {
-
- private 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(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 OfflinePlayer offline) {
- // Ensure the player has data
- if (!offline.hasPlayedBefore()) {
- return null;
- }
-
- // Create a profile and entity to load the player data
- GameProfile profile = new GameProfile(offline.getUniqueId(),
- offline.getName() != null ? offline.getName() : offline.getUniqueId().toString());
- MinecraftServer server = ((CraftServer) Bukkit.getServer()).getServer();
- EntityPlayer entity = new EntityPlayer(server, server.getWorldServer(0), profile,
- new PlayerInteractManager(server.getWorldServer(0)));
-
- 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(EntityHuman)
- try {
- WorldNBTStorage worldNBTStorage = (WorldNBTStorage) player.server.getPlayerList().playerFileData;
-
- NBTTagCompound playerData = new NBTTagCompound();
- player.e(playerData);
-
- if (!isOnline()) {
- // Special case: save old vehicle data
- NBTTagCompound oldData = worldNBTStorage.load(player);
-
- if (oldData != null && oldData.hasKeyOfType("Riding", 10)) {
- // See net.minecraft.server.PlayerList#a(NetworkManager, EntityPlayer) and net.minecraft.server.EntityPlayer#b(NBTTagCompound)
- playerData.set("Riding", oldData.getCompound("Riding"));
- }
- }
-
- File file = new File(worldNBTStorage.getPlayerDir(), player.getUniqueID().toString() + ".dat.tmp");
- File file1 = new File(worldNBTStorage.getPlayerDir(), player.getUniqueID().toString() + ".dat");
-
- NBTCompressedStreamTools.a(playerData, new FileOutputStream(file));
-
- if (file1.exists()) {
- file1.delete();
- }
-
- file.renameTo(file1);
- } catch (Exception e) {
- LogManager.getLogger().warn("Failed to save player data for {}", player.getName());
- }
- }
- });
- }
-
- @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) {
- return player.openInventory(inventory.getBukkitInventory());
- }
-
- @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), (byte) 2));
- }
- }
-
- @NotNull
- @Override
- public String getLocale(Player player) {
- return getHandle(player).locale;
- }
-
-}
diff --git a/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/SpecialEnderChest.java b/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/SpecialEnderChest.java
deleted file mode 100644
index dda4e17..0000000
--- a/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/SpecialEnderChest.java
+++ /dev/null
@@ -1,83 +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 .
- */
-
-package com.lishid.openinv.internal.v1_8_R3;
-
-import com.lishid.openinv.internal.ISpecialEnderChest;
-import java.lang.reflect.Field;
-import net.minecraft.server.v1_8_R3.EntityPlayer;
-import net.minecraft.server.v1_8_R3.IInventory;
-import net.minecraft.server.v1_8_R3.InventoryEnderChest;
-import net.minecraft.server.v1_8_R3.InventorySubcontainer;
-import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftInventory;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.Inventory;
-import org.jetbrains.annotations.NotNull;
-
-public class SpecialEnderChest extends InventorySubcontainer implements IInventory, ISpecialEnderChest {
-
- private final InventoryEnderChest enderChest;
- private final CraftInventory inventory = new CraftInventory(this);
- private boolean playerOnline;
-
- public SpecialEnderChest(Player player, Boolean online) {
- super(PlayerDataManager.getHandle(player).getEnderChest().getName(),
- PlayerDataManager.getHandle(player).getEnderChest().hasCustomName(),
- PlayerDataManager.getHandle(player).getEnderChest().getSize());
- this.playerOnline = online;
- EntityPlayer nmsPlayer = PlayerDataManager.getHandle(player);
- this.enderChest = nmsPlayer.getEnderChest();
- this.bukkitOwner = nmsPlayer.getBukkitEntity();
- this.items = enderChest.getContents();
- }
-
- @Override
- public @NotNull Inventory getBukkitInventory() {
- return inventory;
- }
-
- @Override
- public void setPlayerOnline(@NotNull Player player) {
- if (!playerOnline) {
- try {
- EntityPlayer nmsPlayer = PlayerDataManager.getHandle(player);
- this.bukkitOwner = nmsPlayer.getBukkitEntity();
- InventoryEnderChest playerEnderChest = nmsPlayer.getEnderChest();
- Field field = playerEnderChest.getClass().getField("items");
- field.setAccessible(true);
- field.set(playerEnderChest, this.items);
- } catch (Exception ignored) {}
- playerOnline = true;
- }
- }
-
- @Override
- public void setPlayerOffline() {
- playerOnline = false;
- }
-
- @Override
- public boolean isInUse() {
- return !this.getViewers().isEmpty();
- }
-
- @Override
- public void update() {
- super.update();
- enderChest.update();
- }
-
-}
diff --git a/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/SpecialPlayerInventory.java b/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/SpecialPlayerInventory.java
deleted file mode 100644
index 46f0a3b..0000000
--- a/internal/v1_8_R3/src/main/java/com/lishid/openinv/internal/v1_8_R3/SpecialPlayerInventory.java
+++ /dev/null
@@ -1,230 +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 .
- */
-
-package com.lishid.openinv.internal.v1_8_R3;
-
-import com.lishid.openinv.internal.ISpecialPlayerInventory;
-import net.minecraft.server.v1_8_R3.ItemStack;
-import net.minecraft.server.v1_8_R3.PlayerInventory;
-import org.bukkit.craftbukkit.v1_8_R3.inventory.CraftInventory;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.Inventory;
-import org.jetbrains.annotations.NotNull;
-
-public class SpecialPlayerInventory extends PlayerInventory implements ISpecialPlayerInventory {
-
- private final ItemStack[] extra = new ItemStack[5];
- private final CraftInventory inventory = new CraftInventory(this);
- private boolean playerOnline;
-
- public SpecialPlayerInventory(Player bukkitPlayer, Boolean online) {
- super(PlayerDataManager.getHandle(bukkitPlayer));
- this.playerOnline = online;
- this.items = player.inventory.items;
- this.armor = player.inventory.armor;
- }
-
- @Override
- public @NotNull Inventory getBukkitInventory() {
- return inventory;
- }
-
- @Override
- public void setPlayerOnline(@NotNull Player player) {
- if (!playerOnline) {
- this.player = PlayerDataManager.getHandle(player);
- this.player.inventory.items = this.items;
- this.player.inventory.armor = this.armor;
- playerOnline = true;
- }
- }
-
- @Override
- public void setPlayerOffline() {
- playerOnline = false;
- }
-
- @Override
- public boolean isInUse() {
- return !this.getViewers().isEmpty();
- }
-
- @Override
- public ItemStack[] getContents() {
- ItemStack[] contents = new ItemStack[getSize()];
- System.arraycopy(items, 0, contents, 0, items.length);
- System.arraycopy(armor, 0, contents, items.length, armor.length);
- return contents;
- }
-
- @Override
- public int getSize() {
- return super.getSize() + 5;
- }
-
- @Override
- public ItemStack getItem(int i) {
- ItemStack[] is = this.items;
-
- if (i >= is.length) {
- i -= is.length;
- is = this.armor;
- } else {
- i = getReversedItemSlotNum(i);
- }
-
- if (i >= is.length) {
- i -= is.length;
- is = this.extra;
- } else if (is == this.armor) {
- i = getReversedArmorSlotNum(i);
- }
-
- return is[i];
- }
-
- @Override
- public ItemStack splitStack(int i, int j) {
- ItemStack[] is = this.items;
-
- if (i >= is.length) {
- i -= is.length;
- is = this.armor;
- } else {
- i = getReversedItemSlotNum(i);
- }
-
- if (i >= is.length) {
- i -= is.length;
- is = this.extra;
- } else if (is == this.armor) {
- i = getReversedArmorSlotNum(i);
- }
-
- if (is[i] != null) {
- ItemStack itemstack;
-
- if (is[i].count <= j) {
- itemstack = is[i];
- is[i] = null;
- return itemstack;
- } else {
- itemstack = is[i].cloneAndSubtract(j);
- if (is[i].count == 0) {
- is[i] = null;
- }
-
- return itemstack;
- }
- }
-
- return null;
- }
-
- @Override
- public ItemStack splitWithoutUpdate(int i) {
- ItemStack[] is = this.items;
-
- if (i >= is.length) {
- i -= is.length;
- is = this.armor;
- } else {
- i = getReversedItemSlotNum(i);
- }
-
- if (i >= is.length) {
- i -= is.length;
- is = this.extra;
- } else if (is == this.armor) {
- i = getReversedArmorSlotNum(i);
- }
-
- if (is[i] != null) {
- ItemStack itemstack = is[i];
-
- is[i] = null;
- return itemstack;
- }
-
- return null;
- }
-
- @Override
- public void setItem(int i, ItemStack itemstack) {
- ItemStack[] is = this.items;
-
- if (i >= is.length) {
- i -= is.length;
- is = this.armor;
- } else {
- i = getReversedItemSlotNum(i);
- }
-
- if (i >= is.length) {
- i -= is.length;
- is = this.extra;
- } else if (is == this.armor) {
- i = getReversedArmorSlotNum(i);
- }
-
- // Effects
- if (is == this.extra) {
- player.drop(itemstack, true);
- itemstack = null;
- }
-
- is[i] = itemstack;
-
- player.defaultContainer.b();
- }
-
- private int getReversedItemSlotNum(int i) {
- if (i >= 27) {
- return i - 27;
- }
- return i + 9;
- }
-
- private int getReversedArmorSlotNum(int i) {
- if (i == 0) {
- return 3;
- }
- if (i == 1) {
- return 2;
- }
- if (i == 2) {
- return 1;
- }
- if (i == 3) {
- return 0;
- }
- return i;
- }
-
- @Override
- public String getName() {
- if (player.getName().length() > 16) {
- return player.getName().substring(0, 16);
- }
- return player.getName();
- }
-
- @Override
- public boolean hasCustomName() {
- return true;
- }
-
-}
diff --git a/plugin/src/main/java/com/lishid/openinv/OpenInv.java b/plugin/src/main/java/com/lishid/openinv/OpenInv.java
index ba33e94..8137584 100644
--- a/plugin/src/main/java/com/lishid/openinv/OpenInv.java
+++ b/plugin/src/main/java/com/lishid/openinv/OpenInv.java
@@ -42,6 +42,8 @@ import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.Consumer;
+import net.md_5.bungee.api.ChatMessageType;
+import net.md_5.bungee.api.chat.TextComponent;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.Command;
@@ -150,6 +152,20 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
}
}
+ /**
+ * Convert a raw slot number into a player inventory slot number.
+ *
+ *
Note that this method is specifically for converting an ISpecialPlayerInventory slot number into a regular
+ * player inventory slot number.
+ *
+ * @param view the open inventory view
+ * @param rawSlot the raw slot in the view
+ * @return the converted slot number
+ */
+ public int convertToPlayerSlot(InventoryView view, int rawSlot) {
+ return this.accessor.getPlayerDataManager().convertToPlayerSlot(view, rawSlot);
+ }
+
@Override
public boolean disableSaving() {
return this.getConfig().getBoolean("settings.disable-saving", false);
@@ -285,9 +301,21 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
public void sendSystemMessage(@NotNull Player player, @NotNull String key) {
String message = this.languageManager.getValue(key, getLocale(player));
- if (message != null) {
- this.accessor.getPlayerDataManager().sendSystemMessage(player, message);
+ if (message == null) {
+ return;
}
+
+ int newline = message.indexOf('\n');
+ if (newline != -1) {
+ // No newlines in action bar chat.
+ message = message.substring(0, newline);
+ }
+
+ if (message.isEmpty()) {
+ return;
+ }
+
+ player.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message));
}
public @Nullable String getLocalizedMessage(@NotNull CommandSender sender, @NotNull String key) {
@@ -300,7 +328,7 @@ public class OpenInv extends JavaPlugin implements IOpenInv {
private @Nullable String getLocale(@NotNull CommandSender sender) {
if (sender instanceof Player) {
- return this.accessor.getPlayerDataManager().getLocale((Player) sender);
+ return ((Player) sender).getLocale();
} else {
return this.getConfig().getString("settings.locale", "en_us");
}
diff --git a/plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java b/plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java
index 92c86af..1a81491 100644
--- a/plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java
+++ b/plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java
@@ -32,16 +32,14 @@ public interface IPlayerDataManager {
* @param offline the OfflinePlayer
* @return the Player loaded
*/
- @Nullable
- Player loadPlayer(@NotNull OfflinePlayer offline);
+ @Nullable Player loadPlayer(@NotNull OfflinePlayer offline);
/**
* Creates a new Player from an existing one that will function slightly better offline.
*
* @return the Player
*/
- @NotNull
- Player inject(@NotNull Player player);
+ @NotNull Player inject(@NotNull Player player);
/**
* Opens an ISpecialInventory for a Player.
@@ -51,14 +49,18 @@ public interface IPlayerDataManager {
*`
* @return the InventoryView opened
*/
- @Nullable
- InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
+ @Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
- void sendSystemMessage(@NotNull Player player, @NotNull String message);
-
- @NotNull
- default String getLocale(Player player) {
- return player.getLocale();
- }
+ /**
+ * Convert a raw slot number into a player inventory slot number.
+ *
+ *
Note that this method is specifically for converting an ISpecialPlayerInventory slot number into a regular
+ * player inventory slot number.
+ *
+ * @param view the open inventory view
+ * @param rawSlot the raw slot in the view
+ * @return the converted slot number
+ */
+ int convertToPlayerSlot(InventoryView view, int rawSlot);
}
diff --git a/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java
new file mode 100644
index 0000000..8fc6f09
--- /dev/null
+++ b/plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2011-2021 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 .
+ */
+
+package com.lishid.openinv.internal;
+
+import com.lishid.openinv.OpenInv;
+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;
+
+public class OpenInventoryView extends InventoryView {
+
+ private final Player player;
+ private final ISpecialInventory inventory;
+ private final String titleKey;
+ private final String titleDefaultSuffix;
+ private String title;
+
+ public OpenInventoryView(Player player, ISpecialInventory inventory, String titleKey, String titleDefaultSuffix) {
+ this.player = player;
+ this.inventory = inventory;
+ this.titleKey = titleKey;
+ this.titleDefaultSuffix = titleDefaultSuffix;
+ }
+
+ @Override
+ public @NotNull Inventory getTopInventory() {
+ return inventory.getBukkitInventory();
+ }
+
+ @Override
+ public @NotNull Inventory getBottomInventory() {
+ return getPlayer().getInventory();
+ }
+
+ @Override
+ public @NotNull HumanEntity getPlayer() {
+ return player;
+ }
+
+ @Override
+ public @NotNull InventoryType getType() {
+ return inventory.getBukkitInventory().getType();
+ }
+
+ @Override
+ public @NotNull String getTitle() {
+ if (title == null) {
+ HumanEntity owner = getPlayer();
+
+ String localTitle = OpenInv.getPlugin(OpenInv.class)
+ .getLocalizedMessage(
+ owner,
+ titleKey,
+ "%player%",
+ owner.getName());
+ if (localTitle != null) {
+ title = localTitle;
+ } else {
+ title = owner.getName() + titleDefaultSuffix;
+ }
+ }
+
+ return title;
+ }
+
+}
diff --git a/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java b/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java
index 33221f2..eee6686 100644
--- a/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java
+++ b/plugin/src/main/java/com/lishid/openinv/listeners/InventoryListener.java
@@ -16,20 +16,29 @@
package com.lishid.openinv.listeners;
-import com.lishid.openinv.IOpenInv;
+import com.lishid.openinv.OpenInv;
+import com.lishid.openinv.internal.ISpecialPlayerInventory;
import com.lishid.openinv.util.InventoryAccess;
import com.lishid.openinv.util.Permissions;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
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.InventoryAction;
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;
+import org.bukkit.inventory.InventoryView;
+import org.bukkit.inventory.ItemStack;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
/**
* Listener for inventory-related events to prevent modification of inventories where not allowed.
@@ -38,14 +47,14 @@ import org.bukkit.inventory.Inventory;
*/
public class InventoryListener implements Listener {
- private final IOpenInv plugin;
+ private final OpenInv plugin;
- public InventoryListener(final IOpenInv plugin) {
+ public InventoryListener(final OpenInv plugin) {
this.plugin = plugin;
}
@EventHandler
- public void onInventoryClose(final InventoryCloseEvent event) {
+ public void onInventoryClose(@NotNull final InventoryCloseEvent event) {
if (!(event.getPlayer() instanceof Player)) {
return;
}
@@ -58,37 +67,139 @@ public class InventoryListener implements Listener {
}
@EventHandler(priority = EventPriority.LOWEST)
- public void onInventoryClick(InventoryClickEvent event) {
- onInventoryInteract(event);
+ public void onInventoryClick(@NotNull final InventoryClickEvent event) {
+ if (handleInventoryInteract(event)) {
+ return;
+ }
+
+ // Safe cast - has to be a player to be the holder of a special player inventory.
+ Player player = (Player) event.getWhoClicked();
+
+ if (event.getAction() != InventoryAction.MOVE_TO_OTHER_INVENTORY) {
+ // All own-inventory interactions require updates to display properly.
+ // Update in same tick after event completion.
+ this.plugin.getServer().getScheduler().runTask(this.plugin, player::updateInventory);
+ return;
+ }
+
+ // Extra handling for MOVE_TO_OTHER_INVENTORY - apparently Mojang no longer removes the item from the target
+ // inventory prior to adding it to existing stacks.
+ ItemStack currentItem = event.getCurrentItem();
+ if (currentItem == null) {
+ // Other plugin doing some sort of handling (would be NOTHING for null item otherwise), ignore.
+ return;
+ }
+
+ ItemStack clone = currentItem.clone();
+ event.setCurrentItem(null);
+
+ // Complete add action in same tick after event completion.
+ this.plugin.getServer().getScheduler().runTask(this.plugin, () -> {
+ player.getInventory().addItem(clone);
+ player.updateInventory();
+ });
}
@EventHandler(priority = EventPriority.LOWEST)
- public void onInventoryDrag(InventoryDragEvent event) {
- onInventoryInteract(event);
+ public void onInventoryDrag(@NotNull final InventoryDragEvent event) {
+ if (handleInventoryInteract(event)) {
+ return;
+ }
+
+ InventoryView view = event.getView();
+ int topSize = view.getTopInventory().getSize();
+
+ // Get bottom inventory active slots as player inventory slots.
+ Set slots = event.getRawSlots().stream()
+ .filter(slot -> slot >= topSize)
+ .map(slot -> plugin.convertToPlayerSlot(view, slot)).collect(Collectors.toSet());
+
+ int overlapLosses = 0;
+
+ // Count overlapping slots.
+ for (Map.Entry newItem : event.getNewItems().entrySet()) {
+ int rawSlot = newItem.getKey();
+
+ // Skip bottom inventory slots.
+ if (rawSlot >= topSize) {
+ continue;
+ }
+
+ int convertedSlot = plugin.convertToPlayerSlot(view, rawSlot);
+
+ if (slots.contains(convertedSlot)) {
+ overlapLosses += getCountDiff(view.getItem(rawSlot), newItem.getValue());
+ }
+ }
+
+ // Allow no overlap to proceed as usual.
+ if (overlapLosses < 1) {
+ return;
+ }
+
+ ItemStack cursor = event.getCursor();
+ if (cursor != null) {
+ cursor.setAmount(cursor.getAmount() + overlapLosses);
+ } else {
+ cursor = event.getOldCursor().clone();
+ cursor.setAmount(overlapLosses);
+ }
+
+ event.setCursor(cursor);
}
- private void onInventoryInteract(InventoryInteractEvent event) {
+ private int getCountDiff(@Nullable ItemStack original, @NotNull ItemStack result) {
+ if (original == null || original.getType() != result.getType()) {
+ return result.getAmount();
+ }
+
+ return result.getAmount() - original.getAmount();
+ }
+
+ /**
+ * Handle common InventoryInteractEvent functions.
+ *
+ * @param event the InventoryInteractEvent
+ * @return true unless the top inventory is the holder's own inventory
+ */
+ private boolean handleInventoryInteract(@NotNull final InventoryInteractEvent event) {
HumanEntity entity = event.getWhoClicked();
+ // Un-cancel spectator interactions.
if (Permissions.SPECTATE.hasPermission(entity) && entity.getGameMode() == GameMode.SPECTATOR) {
event.setCancelled(false);
}
if (event.isCancelled()) {
- return;
+ return true;
}
- Inventory inventory = event.getInventory();
+ Inventory inventory = event.getView().getTopInventory();
- if (InventoryAccess.isPlayerInventory(inventory)) {
- if (!Permissions.EDITINV.hasPermission(entity)) {
- event.setCancelled(true);
- }
- } else if (InventoryAccess.isEnderChest(inventory)) {
+ // Is the inventory a special ender chest?
+ if (InventoryAccess.isEnderChest(inventory)) {
+ // Disallow ender chest interaction for users without edit permission.
if (!Permissions.EDITENDER.hasPermission(entity)) {
event.setCancelled(true);
}
+ return true;
}
+
+ ISpecialPlayerInventory playerInventory = InventoryAccess.getPlayerInventory(inventory);
+
+ // Ignore inventories other than special player inventories.
+ if (playerInventory == null) {
+ return true;
+ }
+
+ // Disallow player inventory interaction for users without edit permission.
+ if (!Permissions.EDITINV.hasPermission(entity)) {
+ event.setCancelled(true);
+ return true;
+ }
+
+ // Only specially handle actions in the player's own inventory.
+ return !event.getWhoClicked().equals(event.getView().getTopInventory().getHolder());
}
}
diff --git a/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java b/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java
index 96f3b7b..fb24552 100644
--- a/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java
+++ b/plugin/src/main/java/com/lishid/openinv/util/InternalAccessor.java
@@ -81,6 +81,7 @@ public class InternalAccessor {
case "v1_8_R3":
case "v1_15_R1":
case "v1_16_R2":
+ return "https://github.com/lishid/OpenInv/releases/tag/4.1.5";
case "v1_16_R3":
default:
return "https://github.com/lishid/OpenInv/releases";
diff --git a/plugin/src/main/resources/plugin.yml b/plugin/src/main/resources/plugin.yml
index ce43adb..767b886 100644
--- a/plugin/src/main/resources/plugin.yml
+++ b/plugin/src/main/resources/plugin.yml
@@ -5,7 +5,7 @@ author: lishid
authors: [Jikoo, ShadowRanger]
description: >
This plugin allows you to open a player's inventory as a chest and interact with it in real time.
-api-version: "1.15"
+api-version: "1.16"
permissions:
OpenInv.any.default:
diff --git a/scripts/generate_changelog.sh b/scripts/generate_changelog.sh
new file mode 100644
index 0000000..72c823d
--- /dev/null
+++ b/scripts/generate_changelog.sh
@@ -0,0 +1,67 @@
+#!/bin/bash
+#
+# Copyright (C) 2011-2021 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 .
+#
+
+# A script for generating a changelog from Git.
+#
+# Note that this script is designed for use in GitHub Actions, and is not
+# particularly robust nor configurable. Run from project parent directory.
+
+# Query GitHub for the username of the given email address.
+# Falls through to the given author name.
+lookup_email_username() {
+ lookup=$(curl -G --data-urlencode "q=$1 in:email" https://api.github.com/search/users -H 'Accept: application/vnd.github.v3+json' | grep '"login":' | sed -e 's/^.*": "//g' -e 's/",.*$//g')
+
+ if [[ $lookup ]]; then
+ echo -n "@$lookup"
+ else
+ echo "$2"
+ fi
+}
+
+# Use formatted log to pull authors list
+authors_raw=$(git log --pretty=format:"%ae|%an" "$(git describe --tags --abbrev=0 @^)"..@)
+readarray -t authors <<<"$authors_raw"
+
+declare -A author_data
+
+for author in "${authors[@]}"; do
+ # Match author email
+ author_email=${author%|*}
+ # Convert to lower case
+ author_email=${author_email,,}
+ # Match author name
+ author_name=${author##*|}
+ if [[ -n ${author_data[$author_email]} ]]; then
+ # Skip emails we already have data for
+ continue
+ fi
+
+ # Fetch and store author GitHub username by email
+ author_data[$author_email]=$(lookup_email_username "$author_email" "$author_name")
+done
+
+# Fetch actual formatted changelog
+changelog=$(git log --pretty=format:"%s (%h) - %ae" "$(git describe --tags --abbrev=0 @^)"..@)
+
+for author_email in "${!author_data[@]}"; do
+ # Ignore case when matching
+ shopt -s nocasematch
+ # Match and replace email
+ changelog=${changelog//$author_email/${author_data[$author_email]}}
+done
+
+echo "GENERATED_CHANGELOG<> "$GITHUB_ENV"
diff --git a/scripts/install_spigot_dependencies.sh b/scripts/install_spigot_dependencies.sh
new file mode 100644
index 0000000..09e93e1
--- /dev/null
+++ b/scripts/install_spigot_dependencies.sh
@@ -0,0 +1,75 @@
+#!/bin/bash
+#
+# Copyright (C) 2011-2021 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 .
+#
+
+# A script for installing required Spigot versions.
+#
+# Note that this script is designed for use in GitHub Actions, and is
+# not particularly robust nor configurable.
+# In its current state, the script must be run from OpenInv's parent
+# project directory and will always install BuildTools to ~/buildtools.
+
+buildtools_dir=~/buildtools
+buildtools=$buildtools_dir/BuildTools.jar
+
+get_spigot_versions () {
+ # Get all submodules of internal module
+ modules=$(mvn help:evaluate -Dexpression=project.modules -q -DforceStdout -P all -pl internal | grep -oP '(?<=)(.*)(?=<\/string>)')
+ for module in "${modules[@]}"; do
+
+ # Get number of dependencies declared in pom of specified internal module
+ max_index=$(mvn help:evaluate -Dexpression=project.dependencies -q -DforceStdout -P all -pl internal/"$module" | grep -c "")
+
+ for ((i=0; i < max_index; i++)); do
+ # Get artifactId of dependency
+ artifact_id=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].artifactId -q -DforceStdout -P all -pl internal/"$module")
+
+ # Ensure dependency is spigot
+ if [[ "$artifact_id" == spigot ]]; then
+ # Get spigot version
+ spigot_version=$(mvn help:evaluate -Dexpression=project.dependencies["$i"].version -q -DforceStdout -P all -pl internal/"$module")
+ echo "$spigot_version"
+ break
+ fi
+ done
+ done
+}
+
+get_buildtools () {
+ if [[ -d $buildtools_dir && -f $buildtools ]]; then
+ return
+ fi
+
+ mkdir $buildtools_dir
+ wget https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -O $buildtools
+}
+
+versions=$(get_spigot_versions)
+echo Found Spigot dependencies: "$versions"
+
+for version in "${versions[@]}"; do
+ set -e
+ exit_code=0
+ mvn dependency:get -Dartifact=org.spigotmc:spigot:"$version" -q -o || exit_code=$?
+ if [ $exit_code -ne 0 ]; then
+ echo Installing missing Spigot version "$version"
+ revision=$(echo "$version" | grep -oP '(\d+\.\d+(\.\d+)?)(?=-R[0-9\.]+-SNAPSHOT)')
+ get_buildtools
+ java -jar $buildtools -rev "$revision"
+ else
+ echo Spigot "$version" is already installed
+ fi
+done