// Path: plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java
// public interface IPlayerDataManager {
// 
//     /**
//      * Loads a Player for an OfflinePlayer.
//      * </p>
//      * This method is potentially blocking, and should not be called on the main thread.
//      *
//      * @param offline the OfflinePlayer
//      * @return the Player loaded
//      */
//     @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);
// 
//     /**
//      * Opens an ISpecialInventory for a Player.
//      *
//      * @param player the Player opening the ISpecialInventory
//      * @param inventory the Inventory
//      *`
//      * @return the InventoryView opened
//      */
//     @Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
// 
//     /**
//      * Convert a raw slot number into a player inventory slot number.
//      *
//      * <p>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);
// 
// }
// 
// Path: api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java
// public interface ISpecialInventory {
// 
//     /**
//      * Gets the Inventory associated with this ISpecialInventory.
//      *
//      * @return the Inventory
//      */
//     @NotNull Inventory getBukkitInventory();
// 
//     /**
//      * Sets the Player associated with this ISpecialInventory online.
//      *
//      * @param player the Player coming online
//      */
//     void setPlayerOnline(@NotNull Player player);
// 
//     /**
//      * Sets the Player associated with this ISpecialInventory offline.
//      */
//     void setPlayerOffline();
// 
//     /**
//      * Gets whether or not this ISpecialInventory is in use.
//      *
//      * @return true if the ISpecialInventory is in use
//      */
//     boolean isInUse();
// 
// }
// 
// Path: plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java
// 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;
//     }
// 
// }


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.lang.reflect.Field;
import net.minecraft.server.v1_16_R3.ChatComponentText;
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.EntityPlayer;
import net.minecraft.server.v1_16_R3.MinecraftServer;
import net.minecraft.server.v1_16_R3.PacketPlayOutOpenWindow;
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
import net.minecraft.server.v1_16_R3.World;
import net.minecraft.server.v1_16_R3.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

        InventoryView view = getView(player, inventory);

        if (view == null) {
            return player.openInventory(inventory.getBukkitInventory());
        }

        Container container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) {
            @Override
            public Containers<?> getType() {
                return getContainers(inventory.getBukkitInventory().getSize());
            }
        };

        container.setTitle(new ChatComponentText(view.getTitle()));
        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();

    }

// Path: plugin/src/main/java/com/lishid/openinv/internal/IPlayerDataManager.java
// public interface IPlayerDataManager {
// 
//     /**
//      * Loads a Player for an OfflinePlayer.
//      * </p>
//      * This method is potentially blocking, and should not be called on the main thread.
//      *
//      * @param offline the OfflinePlayer
//      * @return the Player loaded
//      */
//     @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);
// 
//     /**
//      * Opens an ISpecialInventory for a Player.
//      *
//      * @param player the Player opening the ISpecialInventory
//      * @param inventory the Inventory
//      *`
//      * @return the InventoryView opened
//      */
//     @Nullable InventoryView openInventory(@NotNull Player player, @NotNull ISpecialInventory inventory);
// 
//     /**
//      * Convert a raw slot number into a player inventory slot number.
//      *
//      * <p>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);
// 
// }
// 
// Path: api/src/main/java/com/lishid/openinv/internal/ISpecialInventory.java
// public interface ISpecialInventory {
// 
//     /**
//      * Gets the Inventory associated with this ISpecialInventory.
//      *
//      * @return the Inventory
//      */
//     @NotNull Inventory getBukkitInventory();
// 
//     /**
//      * Sets the Player associated with this ISpecialInventory online.
//      *
//      * @param player the Player coming online
//      */
//     void setPlayerOnline(@NotNull Player player);
// 
//     /**
//      * Sets the Player associated with this ISpecialInventory offline.
//      */
//     void setPlayerOffline();
// 
//     /**
//      * Gets whether or not this ISpecialInventory is in use.
//      *
//      * @return true if the ISpecialInventory is in use
//      */
//     boolean isInUse();
// 
// }
// 
// Path: plugin/src/main/java/com/lishid/openinv/internal/OpenInventoryView.java
// 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;
//     }
// 
// }


// Path: internal/v1_16_R3/src/main/java/com/lishid/openinv/internal/v1_16_R3/PlayerDataManager.java
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.lang.reflect.Field;
import net.minecraft.server.v1_16_R3.ChatComponentText;
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.EntityPlayer;
import net.minecraft.server.v1_16_R3.MinecraftServer;
import net.minecraft.server.v1_16_R3.PacketPlayOutOpenWindow;
import net.minecraft.server.v1_16_R3.PlayerInteractManager;
import net.minecraft.server.v1_16_R3.World;
import net.minecraft.server.v1_16_R3.WorldServer;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.Server;
import org.bukkit.craftbukkit.v1_16_R3.CraftServer;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.InventoryView;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;


        InventoryView view = getView(player, inventory);

        if (view == null) {
            return player.openInventory(inventory.getBukkitInventory());
        }

        Container container = new CraftContainer(view, nmsPlayer, nmsPlayer.nextContainerCounter()) {
            @Override
            public Containers<?> getType() {
                return getContainers(inventory.getBukkitInventory().getSize());
            }
        };

        container.setTitle(new ChatComponentText(view.getTitle()));
        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();

    }

    private @Nullable InventoryView getView(Player player, ISpecialInventory inventory) {