Выполнение рецепта не происходит.

Версия Minecraft
1.12.2
API
Forge
122
4
6
Здорова, буду краток, рецепт и все прилегающее к нему я запилил но проверка в самом выполнение не хочет работать
Recipe:
public class MobRitualRecipe {
    private final ItemStack output;
    private final ImmutableList<Ingredient> inputs;
    private final boolean research;

    private final ImmutableList<BlockPos> positions;
    private final ImmutableList<String> entities;

    public MobRitualRecipe(boolean research, ItemStack output, ImmutableList<BlockPos> positions, ImmutableList<String> entities, Ingredient... inputs) {
        this.research = research;
        this.output = output;

        ImmutableList.Builder<Ingredient> builder = ImmutableList.builder();
        for (Ingredient ing : inputs) builder.add(ing);
        this.inputs = builder.build();

        this.positions = positions;
        this.entities = entities;
    }

    public boolean matches(List<EntityItem> entityItems) {
        List<Ingredient> inputsMissing = new ArrayList<>(inputs);
        for (int i = 0; i < entityItems.size(); i++) {
            ItemStack stack = entityItems.get(i).getItem();
            if (stack.isEmpty()) break;

            int stackIndex = -1;
            for (int j = 0; j < inputsMissing.size(); j++) {
                if (compareStacks(inputsMissing.get(j).getMatchingStacks()[0], stack)) {
                    stackIndex = j;
                    break;
                }
            }
            if (stackIndex != -1) inputsMissing.remove(stackIndex);
            else return false;
        }
        return inputsMissing.isEmpty();
    }

    private boolean compareStacks(ItemStack r, ItemStack s) {
        return r.getItem() == s.getItem() && r.getCount() == s.getCount() && r.getItemDamage() == s.getItemDamage() && ItemNBTHelper.matchTag(r.getTagCompound(), s.getTagCompound());
    }

    public ItemStack getOutput() { return output; }
    public ImmutableList<Ingredient> getInputs() { return inputs; }
    public boolean getResearch() { return research; }

    public ImmutableList<BlockPos> getBlockPos() { return positions; }
    public ImmutableList<String> getEntity() { return entities; }
}
Craft:
public class CraftMobRitual {
    public static final ArrayList<MobRitualRecipe> recipes = new ArrayList<>();

    public static void init() {
        addRecipe(false, new ItemStack(Items.NETHER_STAR),
                ImmutableList.of(
                        new BlockPos(2, 0, 0),
                        new BlockPos(-2, 0, 0),
                        new BlockPos(0, 0, 2),
                        new BlockPos(0, 0, -2)
                ),
                ImmutableList.of(
                        "minecraft:zombie",
                        "minecraft:zombie",
                        "minecraft:zombie",
                        "minecraft:zombie"
                ),
                ing(new ItemStack(Blocks.GOLD_BLOCK)),
                ing(new ItemStack(Items.WATER_BUCKET)),
                ing(new ItemStack(Items.COAL)));
    }

    public static void addRecipe(boolean research, ItemStack output, ImmutableList<BlockPos> positions, ImmutableList<String> entity, Ingredient... inputs) {
        Preconditions.checkArgument(inputs.length <= 6);
        recipes.add(new MobRitualRecipe(research, output, positions, entity, inputs));
    }

    private static Ingredient ing(ItemStack stack) { return Ingredient.fromStacks(stack); }
    private static Ingredient nbtIng(ItemStack stack) { return IngredientNBT.fromStacks(stack); }
}
Event:
@Override
    public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer p, EnumHand hand, EnumFacing facing, float x, float y, float z) {
        if (getTile(world, pos) != null && getTile(world, pos).getTypeRune() == 26 && getTile(world, pos).isRuneStartR()) {
            List<Entity> entities = world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(getTile(world, pos).getPos()).grow(25));
            List<EntityItem> list_items = new ArrayList<EntityItem>();

            if (!entities.isEmpty()) for (Entity entity : entities) {
                if (entity instanceof EntityItem) {
                    EntityItem item = (EntityItem) entity;
                    if (item.getDistanceSq(item) <= 2 * 2) {
                        list_items.add(item);
                    }
                }
                if (!list_items.isEmpty()) for (EntityItem item : list_items) {
                    for (MobRitualRecipe recipe : CraftMobRitual.recipes) {
                        if (recipe.matches(list_items) && isTestMob(pos, world, entities, recipe.getBlockPos(), recipe.getEntity())) {
                            System.out.println("yes");
                        }
                    }
                }
            }
            return true;
        }
        return false;
    }

    private static boolean isTestMob(BlockPos pos, World world, List<Entity> entities, ImmutableList<BlockPos> positions, ImmutableList<String> mobID) {
        for (int i = 0; i < positions.size(); i++) {
            BlockPos mPos = pos.add(positions.get(i));
            EntityEntry entry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(mobID.get(i)));
            if (entry == null) return false;

            for (Entity ent : entities) if (ent instanceof EntityLivingBase) {
                EntityLivingBase livingBase = (EntityLivingBase) ent;
                if (!testMob(mPos, world, livingBase, entry)) return false;
            }
        }
        return true;
    }

    private static boolean testMob(BlockPos pos, World world, EntityLivingBase base_list, EntityEntry mob) {
        Entity entity = mob.newInstance(world);
        entity.setPosition(pos.getX(), pos.getY(), pos.getZ());
        if (base_list.getPosition().equals(pos) && base_list.equals(entity)) {
            return true;
        }
        return false;
    }
скажу сразу не работает только метод testMob, должно работать так: в крафте задаются параметры какой моб и на какой позиции, дальше он сравнивается с мобами из листа если есть совпадение по позиции и какой моб то выполняется крафт. Подсобите в этой ситуации.
 
Последнее редактирование:
1,038
57
229
что в отладке? меня смущает только newInstance, звучит очень не двойственно. Будто ты спавнишь. А спавн, по идее сразу должен содержать позицию, при телепортации его может и кикнуть. При том, спавн, это пакет. Просто так в мире сразу ничего не происходит, требуется не только время для прохождения пакета, но и важность сторон (клиент, сервер) на которых это произошло.
 
Последнее редактирование:
122
4
6
спавна нет, происходит следующее есть список рецептов, в нем задается один или несколько мобов с позицией ImmutableList.of( new BlockPos(2, 0, 0), new BlockPos(-2, 0, 0), new BlockPos(0, 0, 2), new BlockPos(0, 0, -2) ), ImmutableList.of( "minecraft:zombie", "minecraft:zombie", "minecraft:zombie", "minecraft:zombie" ) моб и позиция может быть любая, нового моба создаваться не должно, нужно просто сравнить список мобов List<Entity> entities = world.getEntitiesWithinAABB(Entity.class, new AxisAlignedBB(getTile(world, pos).getPos()).grow(25)); и уже с помощью него сравниваются мобы и позиция их, каждая позиция относится к определенному мобу, только вот само сравнение ни как не получается.
а отладка пустая ни крашей ни чего, просто не получается сравнение
 
122
4
6
сори, по отладке
Java:
private static boolean isTestMob(BlockPos pos, World world, List<Entity> entities, ImmutableList<BlockPos> positions, ImmutableList<String> mobID) {
        for (int i = 0; i < positions.size(); i++) {
            BlockPos mPos = pos.add(positions.get(i));
            EntityEntry entry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(mobID.get(i)));
            if (entry == null) return false;

            for (Entity ent : entities) if (ent instanceof EntityLivingBase) {
                EntityLivingBase livingBase = (EntityLivingBase) ent;
                if (!testMob(mPos, world, livingBase, entry)) return false;
            }
        }
        return true;
    }
mPos получает все 4 позиции, entry так же показывает список заданных существ, livingBase так же выдает всех мобов и их позиции, но вот метод testMob не хочет сравнивать все полученные данные, либо я путаю в коде что не хочет сравнивать
 
122
4
6
дебажишь дальше.
там тоже все верно, просто не получается сравнить список с полученным мобом и его позицией из списка


вот часть с проверкой
Java:
for (Entity ent : entities) if (ent instanceof EntityLivingBase) {
                System.out.println(ent.getClass() + " " + ent.getPosition());
                if (!testMob(mPos, world, ent, entry)) return false;
            }
class net.minecraft.entity.monster.EntityZombie BlockPos{x=15, y=4, z=-4} [21:45:04] [Server thread/INFO] [STDOUT]: [lots_of_recipes.init.blocks.Runes:isTestMob:168]: class net.minecraft.entity.monster.EntityZombie BlockPos{x=13, y=4, z=-2} [21:45:04] [Server thread/INFO] [STDOUT]: [lots_of_recipes.init.blocks.Runes:isTestMob:168]: class net.minecraft.entity.monster.EntityZombie BlockPos{x=15, y=4, z=0} [21:45:04] [Server thread/INFO] [STDOUT]: [lots_of_recipes.init.blocks.Runes:isTestMob:168]: class net.minecraft.entity.monster.EntityZombie BlockPos{x=17, y=4, z=-2}
 
Последнее редактирование:
1,038
57
229
ну дык залазь в testMob и говори какой результат или что возвращает.
чему равна entity и т.д.
1699387159750.png
EntityLivingBase это же не список, почему base_list?

сделай переменные для всего этого, сравнивай чему они равны
var pos2 = base_list.getPosition()
var entity2 = base_list
они в принципе могут отличаться entity и entity2, даже если instanceof будет один и тот же, у них разные данные. Где вывод?
Режим отладки - это запуск с жуком, где ты можешь шагать построчно по коду и шагая на следующую строку можешь смотреть что лежит в каждой из переменных. Проще говоря, если я заспавню двух жителей и сравню их или это будут стрелы, то их сравнение как equal никогда не вернёт true. Потому что им даются разные ID, Villager@13 и Villager@2343. Но если ты сравнишь (== или equals ) их getClass() то они будут идентичны
Пчёлки (System.out.println) это в общем то прошлый век. Машинки сейчас серьёзные и отладка это лучший способ проверить не 1, а сразу все переменные и что происходит в каждой строке код или точнее после каждой строки кода. Где останавливаемся, после какого return вышли из метода и т.д.
 
Последнее редактирование:
1,038
57
229
И ещё, если ты у двух заспавненных только что жителей в одну точку сравнишь позиции они будут отличаться, потому что рассталкают друг друга. Поэтому же, == сравнивая их позиции скажет что это разные жители. Он сравнивает каждый параметр объекта.
На сколько я помню в Java equals проверяет только строковые выражение, то есть для сравнении он переводит в строку оба объекта (кстати этот метод public toString() {...} можно переписать через Override. Но в общем то не столь важно сейчас. Если ты оба объекта выведешь через System.out.println() то и сам увидишь что они имеют разные имена в конце, а это ой как важно (Java и без того регистрозависимая).

Вообще, в принципе, не имей привычку сравнивать float или даже double числа в открытую через == (можешь использовать >= или <=). Два одних и тех же числа могут отличаться из-за особенностей плавающей запятой. Для сравнения есть специальный метод, так называемое число эпсилон, в рамках которого (а по сути говорящее что разница не может быть больше чем это число).
if (Double.compare(d1, d2) == 0) { System.out.println("d1 и d2 близки"); }


private final static double EPSILON = 0.00001; /** * Returns true if two doubles are considered equal. Tests if the absolute * difference between two doubles has a difference less then .00001. This * should be fine when comparing prices, because prices have a precision of * .001. * * @param a double to compare. * @param b double to compare. * @return true true if two doubles are considered equal. */ public static boolean equals(double a, double b){ return a == b ? true : Math.abs(a - b) < EPSILON; }


К слову, если одно число ты вычислишь, а с приравненным будешь сравнивать, они будут не равны, как бы странно это не звучало.
float a = 7.0f a += 3.0f float b = 10.0f if(a == b) { //a изначально будет равно 7.0000000000001f //a += 3.0f будет представлено как 3.000000000001f ///и по итогу получится //10.00000000000002f //Поэтому сюда мы никогда не попадём }
Поэтому всегда проще сравнить расстояние, Vector.length или что то такое. (sqrt(катет квадратный + катет квадратный), классическая формула про гипотенузу треугольника). Для тебя подойдет даже большее число, как 1.0f или 1.0d. Типо если мы на расстоянии 1 блока, то типо всё ок. Можно и поменьше, если всё будет хорошо.

Если BlockPos округляет до целых (int или Integer), тогда всё норм. Но всё же есть вероятность что в конце концов они могут заспавниться чуть выше или чуть ниже или немного упасть после спавна или быть вытолкнутыми из мешающего блока. В общем они точно не будут там где ты им сказал появится, хоть и близко к этому.
 
Последнее редактирование:
122
4
6
кое что удалось но не до конца
Java:
private static boolean isTestMob(BlockPos pos, World world, Entity ent, ImmutableList<BlockPos> positions, ImmutableList<String> mobID) {
        for (int i = 0; i < positions.size(); i++) {
            BlockPos mPos = pos.add(positions.get(i));
            EntityEntry entry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(mobID.get(i)));
            if (entry == null) return false;
            if (!testMob(mPos, world, ent, entry)) return false;
        }
        return true;
    }

    private static boolean testMob(BlockPos pos, World world, Entity base_list, EntityEntry mob) {
        int x = pos.getX(), y = pos.getY(), z = pos.getZ();
        Entity entityMob = mob.newInstance(world);
        entityMob.setPosition(x, y, z);

//        System.out.println(base_list.getClass().equals(entityMob.getClass()) + " class");
//        System.out.println(base_list.getPosition().equals(pos) + " pos");
//        System.out.println(base_list.getPosition().equals(entityMob.getPosition()) + " pos mob");

        if (base_list.getClass().equals(entityMob.getClass()) && base_list.getPosition().equals(pos) && base_list.getPosition().equals(entityMob.getPosition())) {
            return true;
        }
        return false;
    }
теперь проверка выполняется но, выполняется только для одной сущности на одних кордах, а все остальные корды не откликаются на вот этом моменте entityMob.setPosition(x, y, z);
 
122
4
6
позиции они будут отличаться,
да на этот щет я не сравниваю float позиции и больше одного моба на одну позицию не может быть.
Но всё же есть вероятность что в конце концов они могут заспавниться чуть выше или чуть ниже
на этот счет не нужно переживать, ведь сам процесс крафта происходить, типа как у культистов, они стоят по кругу возле места проведения, а в моем случае это мобы стоят возле блока тайла по определенным точкам и стоять они могут только так где заданы корды
 
Последнее редактирование:
1,038
57
229
теперь проверка выполняется но, выполняется только для одной сущности на одних кордах, а все остальные корды не откликаются на вот этом моменте entityMob.setPosition(x, y, z);
ты вроде этого и хотел судя по коду?
цифры всегда проверяй через сравнение или через разницу (Math.abs(a-b) < EPSILON)

equals неявно преобразовывает тип к сравнению, как то это называется по научному.. приведение типа, такое же как если бы ты написал
(String)Object, то что компилятор пишет это за тебя, это не плюс к коду и не минус, НО надо всегда понимать что на самом деле будет. А будет вызов Object.toString()

Посмотрел BlockPos чистый int с перезаписанным toString, а значит их сравнение что == что equals, равнозначны. А ещё есть hashcode, который при одних и тех же числах дадут одно и тоже значение.

значит ошибка так и не исчезла. Ты самое главное не вывел в консоль, base_list и его позицию
 
122
4
6
у меня получилось решить данную проблему, изначально я хотел делать проверку и сравнение там где происходит выполнение рецепта, но мне пришла более интересная идея записывать в лист как мобов в округе тайла так и полученных мобов из рецепта

Java:
public boolean matchesMob(List<Entity> entities, BlockPos pos, World world) {
        List<Entity> entities1Missing = new ArrayList<>(getMob(pos, world));
        for (int i = 0; i < entities.size(); i++) {
            Entity entity = entities.get(i);
            if (entity == null) break;

            int mobIndex = -1;
            for (int j = 0; j < entities1Missing.size(); j++) {
                if (compareMobs(entities1Missing.get(j).getLowestRidingEntity(), entity)) {
                    mobIndex = j;
                    break;
                }
            }
            if (mobIndex != -1) entities1Missing.remove(mobIndex);
            else return false;
        }
        return entities1Missing.isEmpty();
    }

    public List<Entity> getMob(BlockPos pos, World world) {
        List<Entity> list_mobs = new ArrayList<Entity>();
        for (int i = 0; i < entities.size(); i++) {
            BlockPos mPos = pos.add(getBlockPos().get(i));
            EntityEntry entry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(getEntity().get(i)));
            if (entry == null) break;
            Entity ent = entry.newInstance(world);
            ent.setPosition((int) mPos.getX(), (int) mPos.getY(), (int) mPos.getZ());
            list_mobs.add(ent);
        }
        return list_mobs;
    }

    private boolean compareMobs(Entity r, Entity s) {
        return r.getClass().equals(s.getClass()) &&
                (int) r.getPosition().getX() == (int) s.getPosition().getX() &&
                (int) r.getPosition().getY() == (int) s.getPosition().getY() &&
                (int) r.getPosition().getZ() == (int) s.getPosition().getZ();
    }
короче я пришел к такому рабочему варианту, но есть небольшой трабл если в рецепте присутствуют разные типы мобов допустим агрессивный типа зомби и мирный моб типа свинья, то при активации код проверки срабатывает если стоишь в дали от центра или в стороне там где зомби, а если в стороне где свинья то отработки кода не происходит хотя крафт правильный
 
1,038
57
229
срабатывание происходить только с одной стороны
расстояние сравни в таких случаях и всё поймешь. у блоков начало и конец примерно в одном месте. Не в центре куба, как это может показаться. А значит ближе к концу при округлении 0.5 (а именно это делает (int))
float a = 0.5f;
int b = (int)a;
, будет 1. Что уже начало нового блока. Всё равно что использовать Math.ceil() который округляет любые искажения, даже 0.1 будет 1 при округлении. (int) немного помягче, более к школьной версии округления.
 
Последнее редактирование:
88
3
54
расстояние сравни в таких случаях и всё поймешь. у блоков начало и конец примерно в одном месте. Не в центре куба, как это может показаться. А значит ближе к концу при округлении 0.5 (а именно это делает (int))
float a = 0.5f;
int b = (int)a;
, будет 1. Что уже начало нового блока. Всё равно что использовать Math.ceil() который округляет любые искажения, даже 0.1 будет 1 при округлении. (int) немного помягче, более к школьной версии округления.
Хоспаде, ну вы хотя бы внимательно читайте и проверяйте свой текст перед отправкой, особенно когда пытаетесь кого-то учить. Иногда бывает, что у вас есть полезная информация, которую вы хотите передать, но вы делаете это так грязно и хаотично, что лучше было бы, если бы человек остался в неведении, чем был ещё больше запутан.

Координаты блоков соответствуют начальным координатам тайла, на котором они находятся. Например, если блок занимает тайл с координатами (3,3,3) - (4,4,4), то его BlockPos будет (3,3,3).

Метод Math.ceil выполняет округление в большую сторону.
Метод Math.floor выполняет округление в меньшую сторону.
Метод Math.round выполняет округление до ближайшего целого числа.

(int) 1.8F вернёт единицу, так как по умолчанию происходит округление в меньшую сторону.

Изначально проблема метода testMob заключалась в том, что equals сравнивал не типы мобов, а два конкретных объекта и их хеш код. Два разных экземпляра Entity никогда не вернут true через equals, так как это разные объекты, занимающие разную область памяти. Корректное сравнение типов, обмазанное правильным расчетом дистанции с учётом особенностей координат тайловой сетки решит все проблемы.
 
Последнее редактирование:

will0376

Токсичная личность
2,152
55
617
(int) 1.8F вернёт единицу, так как по умолчанию происходит округление в меньшую сторону.
округления в этом случае вообще не происходит. int обрежет к ебеням дробную часть и всё тут.
 
88
3
54
округления в этом случае вообще не происходит. int обрежет к ебеням дробную часть и всё тут.
Дак это понятно, я для простоты понимания ассоциировал результат каста с одним из методов округления, о которых говорилось двумя словами ранее.
 
122
4
6
Два разных экземпляра Entity никогда не вернут true через equals, так как это разные объекты, занимающие разную область памяти. Корректное сравнение типов
base_list.getClass().equals(entityMob.getClass()) && base_list.getPosition().equals(pos) && base_list.getPosition().equals(entityMob.getPosition()))
сравнивались не энтити а определенные части из них, такие как позиция и что за моб, а если проходится по всем позициям то да true не получишь. Я от этой идее отошел. Решил просто записывать мобов которые находятся в радиусе, а также записывать не существующего моба которого получаю из рецепта
EntityEntry entry = ForgeRegistries.ENTITIES.getValue(new ResourceLocation(getEntity().get(i)));
if (entry == null) break;
Entity ent = entry.newInstance(world);
ent.setPosition((int) mPos.getX(), (int) mPos.getY(), (int) mPos.getZ()); и все получилось. Но я хз почему при активации крафта выдача в консоль yes происходит только с одной стороны где стоит игрок хотя сам игрок должен пропускаться по сколько он не является нужным классом моба и его позиция не соответствует рецепту private boolean compareMobs(Entity r, Entity s) { return r.getClass().equals(s.getClass()) && (int) r.getPosition().getX() == (int) s.getPosition().getX() && (int) r.getPosition().getY() == (int) s.getPosition().getY() && (int) r.getPosition().getZ() == (int) s.getPosition().getZ(); } если что демонстрация что не работает была показана в видео чуть ранее.
 
1,038
57
229
помогать то в общем то больше и не кому

что лучше было бы, если бы человек остался в неведении
тоже думал на эту тему. Рассчитать КПД. Не будешь же с каждым в личке общаться и помогать, меня так на всех не хватит.

Два разных экземпляра Entity никогда не вернут true через equals, так как это разные объекты, занимающие разную область памяти.
могу доказать обратное, если интересно...
equals неявно преобразовывает тип к сравнению, как то это называется по научному.. приведение типа, такое же как если бы ты написал
(String)Object, то что компилятор пишет это за тебя, это не плюс к коду и не минус, НО надо всегда понимать что на самом деле будет. А будет вызов Object.toString()
(кстати этот метод public toString() {...} можно переписать через Override.
Я к тому что мы все люди и это уже не просто грамматическая ошибка, а ещё мы иногда считаем что в чём то умнее.

А на счёт этого, да, ступил. Выше по этому тексту ошиблись вы , ниже ошибся я, такое бывает. В общем то это ошибка по не знанию конечно, не так страшно потому, что мы все учимся и все делаем такие ошибки на протяжении пути.
(int) 1.8F вернёт единицу

А в остальном вы очень много меня продублировали, но почему то написали так, будто этого ещё не было написано до вас.
Владение почти всеми языками программирования (кроме может 5и: Scala, Kotlin, Go, F# - их я не знаю), 3д моделирования и прочей информации которая ещё со времён Assembler Z80 делает в моей голове небольшую кашу. Так что да, я ошибаюсь. Соревноваться тоже как бы бессмысленно, разве что только с Фолычом (@GloomyFolken), @hohserg, @timaxa007, @tox1cozZ, @CMTV, да @Oldestkon (aka ZnW). С этими ребятами мы по крайней мере близки в знания по Minecraft (хотя это лишь мои догадки, в чём то они меня даже обскакали).
А с Вами у нас совершенно разный опыт и пути.

Поправляйте меня если я ошибаюсь, тут я даже спорить не буду. Потому что ценность информации в её точности, но дальше лезть не советую. Потому что однажды помощь понадобиться и Вам и помочь кроме меня будет некому, такое тоже бывает. Когда ты упираешься в такие темы, которые обычно помогают только за деньги. Слишком узкие или очень "тайные" где требуется именно разносторонний опыт))
 
Последнее редактирование:
Сверху