Помогите WorldEdit#EditSession#countBlocks

Exception_Prototype

Активный участник
Пользователь
Баллы
96
Всем ку, такой вопрос возник по WorldEdit 1.7.10:
Задача: При каждой установке или разрушение блока в привате посчитать количество этого блока в регионе.

Мой код подсчёта блока в привате:
PHP:
    private final EditSession editSession;
 
    public SomeClass(World world) {
        this.editSession = WorldEdit.getInstance().getEditSessionFactory().getEditSession(world, -1);
        this.editSession.setFastMode(true);
    }
 
    public int countBlock(Region region, Material material, short data) {
        return this.editSession.countBlocks(region, Collections.singleton(new BaseBlock(material.getId(), data)));
    }
Я задался вопросом, как лучше использовать EditSession:
1. Создавать для каждого просчёта новую - отпадает сразу, глупость.
2. Получать EditSession игрока, для которого идёт просчёт.
3. Создать один экземпляр EditSession при запуске плагина и считать всё в нем.

Больше всего нравится третий вариант, но тут возникает вопрос, будет ли дополнительная нагрузка, если все подсчёты блоков будут происходить в одном EditSession?
Что думаете? Как лучше поступить?

P.S.
- увы, но нет возможности поставить FAWE.
- fastmode(true) вырубает истории(они нафиг не нужны).
 
Последнее редактирование:
В любом случае ты получишь итерацию по блокам в регионе синхронно, что даст тебе нехилую нагрузку в общей ситуации. Разве что распределять подсчеты по лимитам на какое то время. И скорее EditSession нафиг не нужен, только дополнительные ресурсы на парсинг блоков.
 
Ну почему к примеру при установки огромного кол-ва блоков сервер не крашится, а при ручном setType() ляжет? У него свои оптимизации, очереди, кеши.
 
Ну почему к примеру при установки огромного кол-ва блоков сервер не крашится, а при ручном setType() ляжет? У него свои оптимизации, очереди, кеши.
По моему такое только у fawe есть, никак у we.
 
Ну почему к примеру при установки огромного кол-ва блоков сервер не крашится, а при ручном setType() ляжет? У него свои оптимизации, очереди, кеши.
По моему такое только у fawe есть, никак у we.
Именно так. Если поставить через WE достаточно блоков, сервер зафризит до таймаута.
Просто возьми и глянь сурсы, там любая операция идет через Visitor, который итерирует каждый блок региона и выполняет заданную функцию. Ничего сверх особенного. Единственное это свои врапперы и т.п.
 
Последнее редактирование:
Но вернемся к вопросам. А почему создавать отдельную сессию для каждого просчета плохо? Вроде в ней нет ничего такого, чтобы могло нагрузить хотя бы на миллисекунду. Короче проблема с производительностью скорее возникнет на этапе массивного подсчета блоков во многих регионах (здесь решения через кеш и распределения подсчета блоков на время, кстати можешь переопределить сессию и немного оптимизировать что нужно), а создавать сессии можно и не жалко. Все равно их GC уберет как только отпадут.

Иногда жадность к ресурсам и памяти может заесть так, что за каждый байт и наносекунду сидишь днями думаешь над оптимизациями. Не всегда это хорошо. Важно оценивать все объективно.
 
Последнее редактирование:
Но вернемся к вопросам. А почему создавать отдельную сессию для каждого просчета плохо? Вроде в ней нет ничего такого, чтобы могло нагрузить хотя бы на миллисекунду. Короче проблема с производительностью скорее возникнет на этапе массивного подсчета блоков во многих регионах (здесь решения через кеш и распределения подсчета блоков на время, кстати можешь переопределить сессию и немного оптимизировать что нужно), а создавать сессии можно и не жалко. Все равно их GC уберет как только отпадут.

Иногда жадность к ресурсам и памяти может заесть так, что за каждый байт и наносекунду сидишь днями думаешь над оптимизациями. Не всегда это хорошо. Важно оценивать все объективно.
Так он и оценивает. К чему создавать постоянно сессию, когда она делает одно и то же.
Одна сессия на один плагин, больше нам и не нужно.
 
Но вернемся к вопросам. А почему создавать отдельную сессию для каждого просчета плохо? Вроде в ней нет ничего такого, чтобы могло нагрузить хотя бы на миллисекунду. Короче проблема с производительностью скорее возникнет на этапе массивного подсчета блоков во многих регионах (здесь решения через кеш и распределения подсчета блоков на время, кстати можешь переопределить сессию и немного оптимизировать что нужно), а создавать сессии можно и не жалко. Все равно их GC уберет как только отпадут.

Иногда жадность к ресурсам и памяти может заесть так, что за каждый байт и наносекунду сидишь днями думаешь над оптимизациями. Не всегда это хорошо. Важно оценивать все объективно.
Окей, допустим. Планируется лимитировать только TileEntity, поэтому, что если брать рг и пробегаться по его чанкам и в каждом чанке делать chunk.getTileEntities(). Как бы по всем блокам не бегаем, только по TileEntiy. Что скажите? Как Вам такой вариант?

PHP:
public int getCount(World world, ProtectedRegion region, Material material, byte data) {

        final int minX = region.getMinimumPoint().getBlockX() >> 4;
        final int minZ = region.getMinimumPoint().getBlockZ() >> 4;
        final int maxX = region.getMaximumPoint().getBlockX() >> 4;
        final int maxZ = region.getMaximumPoint().getBlockZ() >> 4;

        //debug(String.format("Request to search: %s %d", material.name(), data));

        int count = 0;

        for (int x = minX; x <= maxX; x++) {
            for (int z = minZ; z <= maxZ; z++) {
                final Chunk chunk = world.getChunkAt(x, z);
                final BlockState[] tiles = chunk.getTileEntities();
                if (tiles != null) {
                    for (BlockState blockState : tiles) {
                        final Block block = blockState.getBlock();
                        //debug(String.format("Tile: %s %d", block.getType().name(), block.getData()));
                        if ((block.getType() == material)) {
                            if ((data == -1) || (block.getData() == data)) {
                                count++;
                            }
                        }
                    }
                }
            }
        }

        //debug("getCount#count: " + count);
        return count;
    }
 
Последнее редактирование:
Окей, допустим. Планируется лимитировать только TileEntity, поэтому, что если брать рг и пробегаться по его чанкам и в каждом чанке делать chunk.getTileEntities(). Как бы по всем блокам не бегаем, только по TileEntiy. Что скажите? Как Вам такой вариант?

PHP:
public int getCount(World world, ProtectedRegion region, Material material, byte data) {

        final int minX = region.getMinimumPoint().getBlockX() >> 4;
        final int minZ = region.getMinimumPoint().getBlockZ() >> 4;
        final int maxX = region.getMaximumPoint().getBlockX() >> 4;
        final int maxZ = region.getMaximumPoint().getBlockZ() >> 4;

        //debug(String.format("Request to search: %s %d", material.name(), data));

        int count = 0;

        for (int x = minX; x <= maxX; x++) {
            for (int z = minZ; z <= maxZ; z++) {
                final Chunk chunk = world.getChunkAt(x, z);
                final BlockState[] tiles = chunk.getTileEntities();
                if (tiles != null) {
                    for (BlockState blockState : tiles) {
                        final Block block = blockState.getBlock();
                        //debug(String.format("Tile: %s %d", block.getType().name(), block.getData()));
                        if ((block.getType() == material)) {
                            if ((data == -1) || (block.getData() == data)) {
                                count++;
                            }
                        }
                    }
                }
            }
        }

        //debug("getCount#count: " + count);
        return count;
    }
Можно, если тебе конечно же неважно, входит тот блок в чанке в регион или нет. Плюс есть идеи оптимизации:
Код:
public int getCount(World world, ProtectedRegion region, Material material, byte data) {
    int minX = region.getMinimumPoint().getBlockX() >> 4;
    int minZ = region.getMinimumPoint().getBlockZ() >> 4;
    int maxX = region.getMaximumPoint().getBlockX() >> 4;
    int maxZ = region.getMaximumPoint().getBlockZ() >> 4;
    
    int count = 0;
    
    for (int x = minX; x <= maxX; x++) {
        for (int z = minZ; z <= maxZ; z++) {
            Chunk chunk = world.getChunkAt(x, z);
            for (BlockState blockState : chunk.getTileEntities()) {
                if (blockState.getType() == material && (data == -1 || blockState.getRawData() == data)) {
                    count++;
                }
            }
        }
    }
    
    return count;
}

Еще одно, скорее всего можно пихать BlockStat'ы куда нибудь на обработку в асинхронном потоке, так как это уже снепшоты блоков, а вот получение блока из BlockState уже ведет к повторному обращению к чанку.
 
Спасибо за оптимизированный вариант.

По поводу того, что входил тот блок в чанке в регион, я уже думал над этим, но всё ещё не определился окончательно. По сути - лимитированные блоки нельзя будет поставить за регион(т.е. в глобал). По идее мы ничего не упустим, но если ставить вопрос ребром, то я бы хотел знать, что даст больше нагрузки: проверка того, что TileEntity входит в регион или редкая проверка лишних блоков, которые не вошли в регион но находятся в чанке? Лично я склоняюсь ко второму варианту, а что думаете Вы по этому поводу?

async
Хм, не знал, это можно использовать. Например для async вывода лимитированных блоков игроку(например показать координаты этих блоков, по команде), но в BlockPlaceEvent мне кажется это никак не поможет или я ошибаюсь?
 
По поводу того, что входил тот блок в чанке в регион, я уже думал над этим, но всё ещё не определился окончательно. По сути - лимитированные блоки нельзя будет поставить за регион(т.е. в глобал). По идее мы ничего не упустим, но если ставить вопрос ребром, то я бы хотел знать, что даст больше нагрузки: проверка того, что TileEntity входит в регион или редкая проверка лишних блоков, которые не вошли в регион но находятся в чанке? Лично я склоняюсь ко второму варианту, а что думаете Вы по этому поводу?
Я тоже думаю что второе.

async
Хм, не знал, это можно использовать. Например для async вывода лимитированных блоков игроку(например показать координаты этих блоков, по команде), но в BlockPlaceEvent мне кажется это никак не поможет или я ошибаюсь?
Если ты хочешь юзать асинхрон, в любом случае выйдешь за пределы события.
 
Назад
Верх