Material - универсальный идентификатор типов блоков и предметов

Discussion in 'Обсуждение Nukkit' started by fromgate, 10/8/16.

  1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
Dismiss Notice
We welcome you on our site. This site is devoted to the Nukkit project and all that is connected with him. Here you can communicate, download plugins, also many other things get acquainted! Register the account right now :3
  1. fromgate

    fromgate Administrator

    Messages:
    681
    Likes Received:
    194
    Хочу обсудить один вопрос. Уже довольно давно было решено, что в наккит необходимо реализовать аналог класса Material из баккита.

    Если в двух словах, то суть его заключается в следующем - единый ENUM в котором перечислены все типы предметов, которым сопоставлены id.
    При этои ряд предметов, требующих дополнительных характеристик (вроде редстоун блоков или блоков, которые обладают какой-то пространственной ориентацией, состоянием (включено/выключено)

    Т.е. это выглядело бы примерно так:

    Code:
    public enum Material{
    
    STONE (1, Stone.class);
    // и прочие
    }
    Сам класс описания камня может быть таким:

    Code:
    public class Stone extends MaterialData {
    
    [pre][code]StoneType type;
    
    public Stone(int meta) {
        super(Material.STONE, meta);
        this.type = StoneType.getByData(meta);
    }
    
    public Stone(){
        this(0);
    }
    
    public Stone (StoneType type){
        this (type.getData());
    }
    [/pre]
    }
    [/code]

    При этом, придётся реализовать и подтипы (чтобы была возможность уйти от цифровых значений data в описании предметов:
    Code:
    public enum StoneType {
    STONE (0),
    GRANITE (1),
    GRANITE_POLISHED (2),
    DIORITE (3),
    DIORITE_POLISHED (4),
    ANDESITE (5),
    ANDESTIE_POLISHED (6);
    
    [pre][code]private int meta;
    
    StoneType (int meta) {
        this.meta = meta;
    
    }
    
    public int getData() {
        return this.meta;
    }
    
    public Stone getMaterialData(){
        return new Stone(this.meta);
    }
    
    public static StoneType getByData(int meta) {
        for (StoneType st : StoneType.values())
            if (st.meta == meta) return st;
        return StoneType.STONE;
    }
    [/pre]
    }[/code]

    Это даст возможнось создавать предметы и ставить блоки не заморачиваясь на значениях ID/DATA.
    Например так:

    level.setBlock (location, Material.STONE, new Stone (StoneType.DIORITE));

    НО!

    Мне тут не нравится конструкция new Stone (StoneType.DIORITE));

    Можно конечно подвиды камня реализовать виде статических переменны в классе Stone
    Code:
    public final static Stone STONE = new Stone(3);
    
    Но тут мы теряем преимущества класса энум (и у нас получается своеобразный винегрет - в одном месте энум, а в другом нет) и мне кажется тут можно получить возможные проблемы с тем, что эту статическую переменную при использовании всегда надо будет клонировать (чтобы можно было безболезненно производить операции над изменением только значения data - т.е. поменять тип камня на андезит, например).

    Есть вариант перечислить все типы камней (и соответственно других подобных блоков в Material:

    Code:
    public enum Material{
    STONE (0, 0, Stone.class),
    STONE_GRANITE (0, 1, Stone.class),
    STONE_GRANITE_POLISHED (0, 2, Stone.class),
    STONE_DIORITE (0, 3, Stone.class),
    STONE_DIORITE_POLISHED (0, 4, Stone.class),
    STONE_ANDESITE (0, 5, Stone.class),
    STONE_ANDESTIE_POLISHED (0, 6, Stone.class);
    }
    У этого способа есть следующие преимущества:

    1. ВСЕ виды блоков приведены в одном месте. При разработке плагинов не нужно будет озадачиваться какое значение data у зелёного стекла.
    2. Эти названия могут быть использованы в конфиге и командах. Соответственно команда /give fromgate WOOL_RED будет выдавать именно красную шерсть
    И недостатки.

    1. Всё равно не удасться уйти полностью от дополнительных классов для ряда блоков. К примеру, вместо двух строк LEVER_ON и LEVER_OFF удобнее использовать дополнительный класс, описывающий состояние. Так же для блоков ориентированны по направлению.
    2. Не совсем понятно как реализовывать проверки на схожие предметы, созданные из разных типов материалов - т.е. чтобы сравнивать двери
      WOODEN_DOOR и WOODEN_DOOR_SPRUCE (условно) всё равно надо будет ориентироваться на цифровое значение ID. А это мне не очень нравится :(
    Что думаете? Лучше вводить дополнительные характеристики для униальных предметов или стараться, по возможности, максимально свести их в один класс?
     
    Last edited: 10/8/16
  2. Tee7even

    Tee7even Nukkit Coders Team

    Messages:
    126
    Likes Received:
    27
    А в Bukkit как сделано? Может ответ на поверхности лежит, мало ли.
     
  3. fromgate

    fromgate Administrator

    Messages:
    681
    Likes Received:
    194
    В бакките это осталось недоделанным, фактически.
    Т.е. там в материалах перечислены все предметы с data 0, но при этом не учтены производные. Т.е. есть белая шерсть, а для цветной - надо добавлять data - WOOL:5.

    В ванилле, сейчас все эти числа стали условными - остаются только текстовые идентификаторы. Но как я понимаю, только для базовых предметов:
    /give @p minecraft:wool 1 15 — выдача игроку чёрной шерсти.
     

Share This Page