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

fromgate

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

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

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

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

Code:
public class Stone extends MaterialData {
 
	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());
	}
}
При этом, придётся реализовать и подтипы (чтобы была возможность уйти от цифровых значений data в описании предметов:
Code:
public enum StoneType {
	STONE (0),
	GRANITE (1),
	GRANITE_POLISHED (2),
	DIORITE (3),
	DIORITE_POLISHED (4),
	ANDESITE (5),
	ANDESTIE_POLISHED (6);
 
	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;
	}
}

Это даст возможнось создавать предметы и ставить блоки не заморачиваясь на значениях 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:

Tee7even

Nukkit Coders Team
А в Bukkit как сделано? Может ответ на поверхности лежит, мало ли.
 

fromgate

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

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