- Баллы
- 66
- Имя в Minecraft
- JekaRUS
Всем доброго времени суток. Разговор будет о том, как сравнивать разные инвентари.
Очень часто, я начал видеть такую картину:
Это не плохо, но есть свои нюансы... К примеру, ты в своем плагине создал инвентарь с именем "Супер-Пупер-Инвентарь", и некий Вася создал такой же инвентарь. Игрок нажал по слоту и вам пришел ивент с нажатием по слоту. Далее вы начинаете обрабатывать его. У Васи по нажатию на первый слот игрок немедленно будет забанен, а у тебя выдается деревянный меч. В это и проблема...
Чтобы этого избежать, я покажу 2 способа сравнения.
1) При создании инвентаря есть один параметр (InventoryHolder), его обычно ставят "null", но мы его и будем использовать.
Создадим новый класс с названием "MyCustomInventory" и скажем ему, что он реализует интерфейс InventoryHolder.
Далее нам нужно реализовать один метод интерфейса "InventoryHolder".
В это методе нужно вернуть наш инвентарь. Создаем конструктор для нашего инвентаря, который будет принимать 2 параметра: int rows (кол-во рядов в инвентаре) и String title (название инвентаря).
В конструкторе создаем инвентарь. В качестве параметра "owner", мы передаем "this", то есть мы создатель инвентаря. Также нужно умножить кол-во рядов на 9.
Также в этом классе создаем метод для обработки кликов.
После создания нашего инвентаря, займемся обработкой его.
Создадим класс "InventoryListener" и скажем ему, что он реализует интерфейс "Listener".
Добавим обработчик нажатий в инвентаре.
В нем делаем проверку на "null".
Проверяем, является ли "holder" инвентаря нашим инвентарем, если да, то кастуем его к нашему классу и передаем ему ивент.
Чтобы создать инвентарь и открыть его игроку, пишем так..
Вот и все. Это и есть первый способ.
2) Второй способ будет сложнее, так как использует "Reflection".
Создадим новый класс "InventoryUtils"
Нам понадобиться одно статичное поле типа "Field"
Далее в статичном конструкторе нам нужно получить версию баккита и класс "CraftInventory"
Создадим статичный метод для сравнения инвентарей.
А внутри проверку.
Теперь можно в любом место кода вызвать этот метод для сравнения.
Надеюсь после этого поста вы перестанете сравнивать инвентари по имени.
p.s.: Не умею я оформлять темы...
Очень часто, я начал видеть такую картину:
Код:
@EventHandler
public void onInventoryClickEvent(InventoryClickEvent event) {
if (event.getClickedInventory().getName().equals("...")) {
}
}
Чтобы этого избежать, я покажу 2 способа сравнения.
1) При создании инвентаря есть один параметр (InventoryHolder), его обычно ставят "null", но мы его и будем использовать.
Создадим новый класс с названием "MyCustomInventory" и скажем ему, что он реализует интерфейс InventoryHolder.
Код:
import org.*********ventory.InventoryHolder;
public class MyCustomInventory implements InventoryHolder {
}
Далее нам нужно реализовать один метод интерфейса "InventoryHolder".
Код:
import org.*********ventory.Inventory;
import org.*********ventory.InventoryHolder;
public class MyCustomInventory implements InventoryHolder {
@Override
public Inventory getInventory() {
return null;
}
}
В это методе нужно вернуть наш инвентарь. Создаем конструктор для нашего инвентаря, который будет принимать 2 параметра: int rows (кол-во рядов в инвентаре) и String title (название инвентаря).
В конструкторе создаем инвентарь. В качестве параметра "owner", мы передаем "this", то есть мы создатель инвентаря. Также нужно умножить кол-во рядов на 9.
Код:
import org.bukkit.Bukkit;
import org.*********ventory.Inventory;
import org.*********ventory.InventoryHolder;
public class MyCustomInventory implements InventoryHolder {
private final Inventory inventory;
public MyCustomInventory(int rows, String title) {
this.inventory = Bukkit.createInventory(this, rows * 9, title);
}
@Override
public Inventory getInventory() {
return this.inventory;
}
}
Также в этом классе создаем метод для обработки кликов.
Код:
public void onInventoryClick(InventoryClickEvent event) {
// ...
}
После создания нашего инвентаря, займемся обработкой его.
Создадим класс "InventoryListener" и скажем ему, что он реализует интерфейс "Listener".
Код:
import org.bukkit.event.Listener;
public class InventoryListener implements Listener {
}
Добавим обработчик нажатий в инвентаре.
Код:
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
}
В нем делаем проверку на "null".
Код:
Inventory inventory = event.getClickedInventory();
if (inventory == null || event.getClickedInventory().getHolder() == null) {
return;
}
Проверяем, является ли "holder" инвентаря нашим инвентарем, если да, то кастуем его к нашему классу и передаем ему ивент.
Код:
if (inventory.getHolder() instanceof MyCustomInventory) {
((MyCustomInventory) inventory.getHolder()).onInventoryClick(event);
}
Чтобы создать инвентарь и открыть его игроку, пишем так..
Код:
MyCustomInventory myCustomInventory = new MyCustomInventory(3, "MyCustomInventory");
Player player = ...;
player.openInventory(myCustomInventory.getInventory());
Вот и все. Это и есть первый способ.
2) Второй способ будет сложнее, так как использует "Reflection".
Создадим новый класс "InventoryUtils"
Код:
public class InventoryUtils {
}
Нам понадобиться одно статичное поле типа "Field"
Код:
private static Field field = null;
Далее в статичном конструкторе нам нужно получить версию баккита и класс "CraftInventory"
Код:
static {
try {
// Получаем версию баккита
String version = Pattern.compile("\\.").split(Bukkit.getServer().getClass().getPackage().getName())[3];
// Получаем класс инвентаря
Class<?> mcInventory = Class.forName(String.format("org.bukkit.craftbukkit.%s.inventory.CraftInventory", version));
// Получаем приватное поле "inventory"
field = mcInventory.getDeclaredField("inventory");
// Разрешаем изменять
field.setAccessible(true);
}
catch (ClassNotFoundException | NoSuchFieldException e) {
e.printStackTrace();
}
}
Создадим статичный метод для сравнения инвентарей.
Код:
public static boolean equalsInventory(Inventory i1, Inventory i2) {
}
А внутри проверку.
Код:
try {
return field.get(i1) == field.get(i2);
}
catch (IllegalAccessException ignore) {
return false;
}
Теперь можно в любом место кода вызвать этот метод для сравнения.
Код:
public class InventoryListener implements Listener {
private final Inventory kits;
public InventoryListener() {
// Создаем свой инвентарь
this.kits = Bukkit.createInventory(null, 3 * 9, "kits");
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
// Как только игрок заходит на сервер, открываем игроку наш инвентарь
event.getPlayer().openInventory(this.kits);
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
// Проверяем нажал ли игрок на инвентарь
if (event.getClickedInventory() != null) {
// Сравниваем инвентарь по которому нажали с нашим инвентарем
if (InventoryUtils.equalsInventory(event.getClickedInventory(), this.kits)) {
// your code
}
}
}
}
Надеюсь после этого поста вы перестанете сравнивать инвентари по имени.
p.s.: Не умею я оформлять темы...
Код:
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.*********ventory.Inventory;
public class InventoryListener implements Listener {
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
Inventory inventory = event.getClickedInventory();
if (inventory == null || inventory.getHolder() == null) {
return;
}
if (inventory.getHolder() instanceof MyCustomInventory) {
((MyCustomInventory) inventory.getHolder()).onInventoryClick(event);
}
}
}
Код:
import org.bukkit.Bukkit;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.*********ventory.Inventory;
import org.*********ventory.InventoryHolder;
public class MyCustomInventory implements InventoryHolder {
private final Inventory inventory;
public MyCustomInventory(int rows, String title) {
this.inventory = Bukkit.createInventory(this, rows * 9, title);
}
@Override
public Inventory getInventory() {
return this.inventory;
}
public void onInventoryClick(InventoryClickEvent event) {
// ...
}
}
Код:
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.*********ventory.Inventory;
public class InventoryListener implements Listener {
private final Inventory kits;
public InventoryListener() {
this.kits = Bukkit.createInventory(null, 3 * 9, "kits");
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
event.getPlayer().openInventory(this.kits);
}
@EventHandler
public void onInventoryClick(InventoryClickEvent event) {
if (event.getClickedInventory() != null) {
if (InventoryUtils.equalsInventory(event.getClickedInventory(), this.kits)) {
// your code
}
}
}
}
Код:
import java.lang.reflect.Field;
import java.util.regex.Pattern;
import org.bukkit.Bukkit;
import org.*********ventory.Inventory;
public class InventoryUtils {
private static Field field = null;
static {
try {
String version = Pattern.compile("\\.").split(Bukkit.getServer().getClass().getPackage().getName())[3];
Class<?> mcInventory = Class.forName(String.format("org.bukkit.craftbukkit.%s.inventory.CraftInventory", version));
field = mcInventory.getDeclaredField("inventory");
field.setAccessible(true);
}
catch (ClassNotFoundException | NoSuchFieldException e) {
e.printStackTrace();
}
}
public static boolean equalsInventory(Inventory i1, Inventory i2) {
try {
return field.get(i1) == field.get(i2);
}
catch (IllegalAccessException ignore) {
return false;
}
}
}