В контексте, я работаю над модом Minecraft (1.21, то есть Java 21), цель которого:
99
на максимальный размер стека на куски и замените его чем-то более удобным.Я достиг этих двух целей для N=2ˣ, индивидуально определив, назначив прослушиватель и проверив каждый тег на каждую степень двойки.
public class ModTags{
public static final TagKey<Item> IS_STACK_SIZE_1 = createTag("stack_size_1" );
public static final TagKey<Item> IS_STACK_SIZE_2 = createTag("stack_size_2" );
public static final TagKey<Item> IS_STACK_SIZE_2 = createTag("stack_size_4" );
[...]
public static final TagKey<Item> IS_STACK_SIZE_2048 = createTag("stack_size_2048");
[...]
addReloadListener("stack_size_1" );
addReloadListener("stack_size_2" );
addReloadListener("stack_size_4" );
[...]
addReloadListener("stack_size_2048");
}}
@Mixin(ItemStack.class)
public abstract class ItemStack_SizeMixin implements ComponentHolder, FabricItemStack {
[...]
@Inject(method = "getMaxCount", at = @At("HEAD"))
private void updateMaxStackSizeWithTag(CallbackInfoReturnable<Integer> cir){
ItemStack thisAsStack = (ItemStack)(Object) this;
if ( thisAsStack.isIn(ModTags.Items.IS_STACK_SIZE_2048)) ChangeStackSize(thisAsStack, 2048 );
else if ( thisAsStack.isIn(ModTags.Items.IS_STACK_SIZE_1024)) ChangeStackSize(thisAsStack, 1024 );
[...]
}
}
Стратегия, которая, как я знал, не будет масштабироваться, когда я ее выберу, но наивность которой позволит легко кодировать остальную логику мода, проверьте. Я надеялся, что за то время, которое мне понадобится, чтобы удовлетворительно исправить все остальное, я накопим ноу-хау, чтобы заменить это лучшей системой. Что ж, насколько я могу судить, это время пришло.
А у меня точно не так: мой вопрос,
Как лучше всего систематически определять, хранить и проверять теги предметов Minecraft 2048? Ради людей, которые действительно хотят, чтобы max_stack_size был равен 372?
Я уже пробовал реализовать его как ArrayList, и это постоянно вызывало stackOverflows. Кроме того, у меня просто нет знаний Java, чтобы иметь представление.
Я думаю, первое, что вам следует задуматься: «Действительно ли мне нужно, чтобы люди могли выбирать размер стека 1837?». Какую выгоду получит игрок, выбрав такое произвольное число? То, что вы можете, не означает, что вы должны.
Игроки привыкли к стекам из 1, 16 и 64, поэтому, по своей наивности, я бы сказал: придерживайтесь степеней двойки, этого более чем достаточно. Мало того, это облегчает вашу жизнь, а также жизнь игрока, давая ему меньше бремени выбора. (Я рискую и говорю, что игроков вообще не волнует разный размер стека. Они, вероятно, все равно выбирают максимально возможный размер...)
При этом, имея дело с повторным созданием и чтением объектов, рекомендуется использовать циклы и, возможно, карту, на которой вы можете легко хранить объекты одного и того же типа.
Таким образом, вы также избавитесь от необходимости создавать константу для каждого размера стека.
Я не в курсе моддинга Minecraft, но думаю, что большая часть кода состоит из static
переменных и методов. Кроме того, я не уверен на 100 %, как работает thisAsStack.isIn
, но попытаюсь дать вам отправную точку, как обобщить ваш код и сделать его масштабируемым. Итак, в итоге я бы предложил следующее:
public class ModTags {
/**
* Allows for stack sizes up to 2^11 = 2048
*/
private static final Integer MAX_POWER_OF_TWO = 11;
public static final Map<Integer, TagKey<Item>> STACK_SIZES;
static {
Map<Integer, Object> tmpMap = new HashMap<>();
for(int i = 0; i <= MAX_POWER_OF_TWO; i++) {
int stackSize = 1 << i;
String tagName = "stack_size_" + i;
tmpMap.put(stackSize, createTag(tagName));
addReloadListener(tagName);
}
STACK_SIZES = Collections.unmodifiableMap(tmpMap);
}
...
}
и ваш класс полезности:
...
private void updateMaxStackSizeWithTag(CallbackInfoReturnable<Integer> cir){
ItemStack thisAsStack = (ItemStack)(Object) this;
ModTags.STACK_SIZES.entrySet().stream()
.filter(entry -> thisAsStack.isIn(entry.getValue()))
.findFirst()
.map(Map.Entry::getKey)
.ifPresentOrElse(stackSize -> ChangeStackSize(thisAsStack, stackSize), () -> /* Handle not found here */);
}
Благодаря этому у вас есть общий способ добавления размеров стека со степенью двойки и выполнения всей регистрации и обновления в несколько строк. Больше не нужно создавать сотни подобных констант.
Опять же, поскольку я не уверен на 100%, как все работает в вашем коде, я надеюсь, что смогу дать вам хотя бы основу для работы.
Еще спасибо. Думаю, я понимаю весь этот код и обязательно попытаюсь его использовать. Я полон надежд и отчитаюсь, когда получу что-то, что скомпилируется. Еще раз спасибо.
Сразу понял, что жалуется. Это конечно не корректно, но это ни сюда, ни сюда по поводу заданного мной вопроса. И на то, что я спросил, это определенно идеальный ответ. Спасибо.
Вы правы: игрокам определенно не нужен 1837, а степень двойки будет наиболее интересной. Но причина, по которой мне нужны все цифры, заключается в том, чтобы дать возможность шутникам, не требующим особых усилий, сложить все до 69, 132, 420 или чего-то еще в своем пакете данных для личного использования, оставив меня в стороне. По моему мнению, было бы лучше иметь номера в наличии и никогда не нуждаться в них, чем когда-либо иметь дело с запросами на добавление номера.