Войти или зарегистрироваться
  • Вы находитесь в сообществе Rubukkit. Мы - администраторы серверов Minecraft, разрабатываем собственные плагины и переводим на различные языки плагины наших коллег из других стран.

Стартап Сравниваем инвентари.

JekaRUS

Активный участник
Пользователь
Баллы
66
Имя в Minecraft
JekaRUS
Всем доброго времени суток. Разговор будет о том, как сравнивать разные инвентари.

Очень часто, я начал видеть такую картину:
Код:
    @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;
        }
    }

}
 
А каким образом игрок может в игре создать инвентарь своим именем?
 
Ну он же не сможет прописать коды цветов. Знак параграфа в игре нельзя писать.
1) На сервере могут быть плагины которые разрешают это делать.
2) В самом начале я привел пример: 2 разработчика, не зная друг о друге, создали свои инвентари с одинаковым названием и начали инвентари работать не так как нужно, а еще хуже, ошибки в консоль кидать..
 
Давай чекним нормальные плагины и я уверен, что сравнение идет не по имени в 80%??
ни в одном плагине не видел, чтобы кто-то ипал себе моск тем, что ты тут расписал
 
ни в одном плагине не видел, чтобы кто-то ипал себе моск тем, что ты тут расписал
Сожалею, так как ты смотрел только на ковно-код... Если плагин заточен на гуи и стабильную работу, а не кое-как, то разработчик НИКОГДА не будет сравнивать инвентари по имени..
 

Поделиться этой страницей

Назад
Верх