Моб, привлекаемый светом

Версия Minecraft
1.16.5
API
Forge
198
1
24
Хочу сделать так, чтобы зомби собирались возле факелов, фонарей и т.д.
Для этого решил переделать ИИ поиска воды, чтобы вместо воды искать более освещённые блоки, чем тот, где стоит зомби:

SeekLitAreaGoal.java:
public class SeekLitAreaGoal extends Goal {
    private final MonsterEntity mob;

    public SeekLitAreaGoal(MonsterEntity p_i48936_1_) {
        this.mob = p_i48936_1_;
    }

    public boolean canUse() {
        return true;
    }

    public void start() {
        BlockPos blockpos = null;

        for (BlockPos blockpos1 : BlockPos.betweenClosed(new BlockPos(this.mob.getX()-16,this.mob.getY()-8, this.mob.getZ()-16), new BlockPos(this.mob.getX()+16,this.mob.getY()+8, this.mob.getZ()+16)))
            if (this.mob.level.getBrightness(LightType.BLOCK,blockpos1) > this.mob.level.getBrightness(LightType.BLOCK,this.mob.blockPosition())) {
                blockpos = blockpos1;
                break;
            }

        if (blockpos != null) {
            this.mob.getMoveControl().setWantedPosition((double) blockpos.getX(), (double) blockpos.getY(), (double) blockpos.getZ(), 1.0D);
        }

    }
}

Добавил в RegisterGoals в классе своего зомби:

Zombie1.registerGoals():
@Override
    public void registerGoals() {
        super.registerGoals();
        this.goalSelector.addGoal(2,new SeekLitAreaGoal(this));
    }

Но зомби, похоже, никак не реагируют на факел... Что я делаю неправильно?
 
198
1
24
Всё, больше не нужно. Понял, что постоянно проверять кучу блоков на освещённость - будет адски тормозить. Вместо этого решил сообщать всем зомби в определённом радиусе, когда игрок ставит факелы и т.д. (через BlockEvent.EntityPlaceEvent и MonsterEntity.getNavigation().moveTo() )
 
7,099
324
1,510
Можно искать не каждый тик. Можно в капабилити чанка кешировать позиции установленных факелов
 

tox1cozZ

aka Agravaine
8,456
598
2,892
На 1.7.10:
В чанке метод getBlockLightValue, который берёт кешированное значение из ExtendedBlockStorage#getExtBlocklightValue, который в свою очередь хранить их в blocklightArray.

Метод в мире getBlockLightValue достаёт еще блок по координатам и сравнивает окружающий свет соседних блоков по шести сторонам, выбирая самый светлый из них. Я думаю в нашем случае это можно игнорировать и брать напрямую из чанка (сам чанк по координатам получаем за О(1) из мапы), хотя лучше протестировать.
Остальные данные уже достаются из массивов по индексу, который тоже вычисляется очень быстро.

Думаю не составит труда на новой версии пробежаться и выполнить такой же анализ.
P.S На 1.7.10 можно вызвать метод с последним аргументов false чтобы не проверять соседние блоки. Тогда вообще не придется ковыряться в этом.

Само собой, всё равно не надо каждый тик выполнять поиск. Можно ограничиться раз в секунду.
 
198
1
24
Раз в n секунд (возможно, при автосохранении) искать самый освещённый блок в радиусе и сообщать зомби его координаты?
Хотя, тогда надо придумать, как выбирать из одинаково освещённых блоков. Может, составлять список наиболее освещённых блоков, потом проверять, вокруг которого из них больше всего зомби, и созывать туда всех?
 

tox1cozZ

aka Agravaine
8,456
598
2,892
Раз в n секунд (возможно, при автосохранении) искать самый освещённый блок в радиусе и сообщать зомби его координаты?
Да просто в AI проверять раз в некоторое время блоки в радиусе.

Может, составлять список наиболее освещённых блоков, потом проверять, вокруг которого из них больше всего зомби, и созывать туда всех?
Я бы выбирал самый освещенный блок в радиусе и если он не один - слал зомби к рандомному.
 
7,099
324
1,510
Ну так все равно нужно перебирать блоки в области. А я предложил кешировать позиции источников света. Если список пуст - значит, целей в том чанке нету и ниче перебирать не надо
 

tox1cozZ

aka Agravaine
8,456
598
2,892
Что перебирать-то? Ты не достаешь блоки из мира, хей. Перечитай еще раз моё сообщение. Уровень света на определенных координатах уже закеширован в чанке.
Всё что нужно достать - это чанк по координатам, а чанки лежат в мапе и это за О(1).
 
7,099
324
1,510
Я бы выбирал самый освещенный блок в радиусе и если он не один - слал зомби к рандомному.
Ну так для этого нужно перебрать блокпозы в радиусе и для каждой позиции вызвать getBlockLightValue.
Я понимаю, что проверка света это быстро, но chunk.getCapability(TORCH_CACHE, null).torchPoses.get(0) все же быстрее
 

tox1cozZ

aka Agravaine
8,456
598
2,892
Да какие блокпозы... Ну просто чанк достань по координатам, а у него достань свет.
Как ты эти кеши собрался поддерживать в актуальном состоянии? Свет может и не игрок поставить. И сломать блок тоже. Ивентами ты это не отловишь. Хукаться в setBlock? Ну бред же.
 
7,099
324
1,510
Есть ивент BlockEvent.NeighborNotifyEvent, вызывающийся из World#setBlockState. Если устанавливаемый блок - факел, то добавляем позицию в кеш. Если предыдущий блок - факел, то удаляем позицию из кеша
 
Сверху