Установка блоков многа и быстро

Версия Minecraft
1.12.2
API
Forge
395
34
90
world.setBlockState() ; не вариант он устанавливает 1 блок за тоже время за которое Template 1 структуру и возникает вопрос как какать ставить быстро
 
Последнее редактирование:
Решение
Не удивительно - наговнокодил отменно - естественно оно и будет тормозить

Как минимум
1) Куча лишних обращений к массиву по индексу
2) Используй мутируемую позицию, вместо того, чтобы каждый раз порождать новый объект
3) Куча лишних вызовов world.setBlockState (если структура содержит пустоты)

(Закрою глаза на другие менее очевидные косяки)
world.setBlockState() ; не вариант он устонавливает 1 блок за тоже время за которое Template 1 структуру и возникает вопрос как какать ставить быстро
Если тебе нужно установить ровно 1 блок (и ничего больше) - то там не чего оптимизировать стандартными методами.
+ Те-же Template - проходятся в цикле, рассчитывает поворот, отражение и много раз вызывают world.setBlockState(), оно физически не может быть быстрее простого world.setBlockState()

Однако ... В паре с 1-ой моей приватной оптимизацией, под названием Elca-кеш, и то и другое можно делать в 2-15+ раз быстрее

+ На этапе генерации (не путать с популяцией) можно в чанк-праймер ставить блоки очень быстро, возможно тебе подойдет этот вариант
 
оно физически не может быть быстрее простого world.setBlockState()
Странно, просто делал через world.setBlockState() и одна и таже структура в Template размещалась за ~20ms а через мой цикл за ~1000ms
видимо делал что-то не так
please:
    public IBlockState getBS(int x, int y, int z) {
        return blockStates[z][y][x];
    }

    @Override
    public void please(World world, int xC, int yC, int zC) { // При установке вызывается только этот метод
        for (int z = 0; z != blockStates.length; z++) {
            for (int y = 0; y != blockStates[z].length; y++) {
                for (int x = 0; x != blockStates[z][y].length; x++) {
                    world.setBlockState(new BlockPos(xC + x, yC + y, zC + z), getBS(x, y, z));
                }
            }
        }
    }
 
Последнее редактирование:
Не удивительно - наговнокодил отменно - естественно оно и будет тормозить

Как минимум
1) Куча лишних обращений к массиву по индексу
2) Используй мутируемую позицию, вместо того, чтобы каждый раз порождать новый объект
3) Куча лишних вызовов world.setBlockState (если структура содержит пустоты)

(Закрою глаза на другие менее очевидные косяки)
 
естественно оно и будет тормозить
Я знаю как ещё улучшить этот код. Вместо массива воспользоваться LinkedList<Triplet<Integer, Integer, Integer>>, тогда точно ускорится в 15 раз.

и возникает вопрос как какать ставить быстро
Наилучший вариант - писать свою установку в мир, как уже было сказано выше, ибо сам майн делает это тоже достаточно медленно.
 
Да вы чё, этож лютейшый стёб был над кодом...

LinkedList имеет O(n) на чтение, массив же O(1) (и ArrayList тоже, кстати). Хотя, в данном случае, он не отличается по скорости от связанного списка (и мб даже медленнее), ввиду особенностей хранения многомерных массивов ("первый" работает как надо - хранит все ссылки на массивы последовательно, но вот дальше происходит чухня, из-за которой и созданы "deep" методы в Arrays).
Я уж молчу про затычку в виде Triplet.

Наилучшее решение в данном вопросе - хранить BlockState в одномерном ArrayList/массиве (разницы никакой не должно быть, поскольку и первый, и второй работают с ссылками), а размеры брать из отдельных переменных. Таким образом:
1) Чтение BlockState имеет сложность O(1); - наверное, это и имел ввиду @HomaPlus в п.1 своего сообщения;
2) BlockPos один, но просто смещается в циклах при установке (BlockPos#up, #east, #north и т.д.); - что раньше и сказал @HomaPlus (Mutable BlockPos);
3) Остаётся лишь вопрос установки. - об этом я уже говорил ранее: сам майн устанавливает блоки достаточно медленно;
Единственный минус - читать массив человеку не очень удобно. Соответственно, схожий алго должен быть и на запись структуры.
 
Получилась кастрированная версия Template
CustomGenStructure:
public class CustomGenStructure {
    private static final List<String> rawStructures = new ArrayList<>();
    private static final Map<String, TRAStructure> structures = new HashMap<>();

    public static void put(String name) {
        rawStructures.add(name);
    }

    public static void register() {
        for (String s : rawStructures) {
            structures.put(s, new TRAStructure(s));
        }
        rawStructures.clear();
    }

    public static void please(World world, int x, int y, int z, String name) {
        if (structures.containsKey(name)) {
            structures.get(name).please(world, x, y, z);
        } else {
            throw new RuntimeException("invalid structure name: " + name);
        }
    }

    public static void registerOrPlease(World world, int x, int y, int z, String name) {
        if (structures.containsKey(name)) {
            structures.get(name).please(world, x, y, z);
        } else {
            TRAStructure structure = new TRAStructure(name);
            structures.put(name, structure);
            structure.please(world, x, y, z);
        }
    }
}


public class TRAStructure {
    protected final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();

    protected final LinkedList<BlockInfo> blocks = new LinkedList<>();

    public TRAStructure(String structureName) {
        NBTTagCompound structureNBT = readStructureAsName(structureName);
        NBTTagList palette = structureNBT.getTagList("palette", 10);
        NBTTagList blocksNBT = structureNBT.getTagList("blocks", 10);

        int air = -1;
        IBlockState[] blocksNames = new IBlockState[palette.tagCount()];
        for (int i = 0; i != palette.tagCount(); i++) {
            blocksNames[i] = getBlockByString(palette.getCompoundTagAt(i).getString("Name")).getDefaultState();
            if (getBlockByString(palette.getCompoundTagAt(i).getString("Name")) == Blocks.AIR) {
                air = i;
            }
        }

        for (int i = 0; i != blocksNBT.tagCount(); i++) {
            NBTTagCompound compound = blocksNBT.getCompoundTagAt(i);
            NBTTagList pos = compound.getTagList("pos", 3);
            int state = compound.getInteger("state");
            if (state != air) {
                blocks.add(new BlockInfo(pos.getIntAt(0), pos.getIntAt(1), pos.getIntAt(2), blocksNames[state]));
            }
        }
    }

    private static NBTTagCompound readStructureAsName(String structureName) {
        InputStream inputstream = MinecraftServer.class.getResourceAsStream("/assets/" + Referense.MODID + "/structures/" + structureName + ".nbt");
        try {
            assert inputstream != null;
            return CompressedStreamTools.readCompressed(inputstream);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            IOUtils.closeQuietly(inputstream);
        }
    }

    public void please(World world, int x, int y, int z) {
        for (BlockInfo block : blocks) {
            world.setBlockState(mutablePos.setPos(block.x + x, block.y + y, block.z + z), block.state);
        }
    }

    protected Block getBlockByString(String block) {
        ResourceLocation resourcelocation = new ResourceLocation(block);
        if (!Block.REGISTRY.containsKey(resourcelocation))
        {
            throw new RuntimeException(block);
        }
        else
        {
            return Block.REGISTRY.getObject(resourcelocation);
        }
    }

    protected static class BlockInfo {
        public final int x;
        public final int y;
        public final int z;
        public final IBlockState state;

        public BlockInfo(int x, int y, int z, IBlockState state) {
            this.x = x;
            this.y = y;
            this.z = z;
            this.state = state;
        }
    }
}
которая работает на 30% быстрее чем сам Template но её нужно продолжать вылизывать
+ На этапе генерации (не путать с популяцией) можно в чанк-праймер ставить блоки очень быстро, возможно тебе подойдет этот вариант
и на счёт этого можно ли удалять чанки и имеет ли смысл делать это на постоянной основе т.к.
мне нужно очищать область 16 на 16 чанков и расставлять структуры
 
Последнее редактирование:
Остаётся лишь вопрос установки. - об этом я уже говорил ранее: сам майн устанавливает блоки достаточно медленно;
Это обычными модами не исправить - добро пожаловать в переписывание mojang-кода с помощью asm-a или как-то еще
Одно из узких мест - избыточный перерасчет света - Phosphor +- исправляет это

Единственный минус - читать массив человеку не очень удобно.
Программа собственно в первую очередь нужна чтобы сообщить машине, что она должна делать, а не человеку ... Так что покрыть документацией для себя будущего - и ладно
 
мне нужно очищать область 16 на 16 чанков и заново расставлять структуры
В этом случае подойдет ChunkPrimer (писал выше). Так же в твоем случае можно 1 раз создать чанк-шаблон - и потом замещать копией этого чанка уже существующий чанк в мире
 
Можно ещё попробовать вот такую штуку. Без всяких лишних проверок на состояния и т.д.

Java:
ExtendedBlockStorage ebs = world.getChunkFromBlockCoords(pos).getBlockStorageArray()[pos.getY() >> 4];
if (ebs != Chunk.NULL_BLOCK_STORAGE) ebs.set(pos.getX() & 15, pos.getY() & 15, pos.getZ() & 15, state);

Но учти, что тут не происходит ни пересчёта света ни разных иных операций, которые необходимы для нормальной работы игры.
Поэтому я юзаю данный метод лишь для замены однотипных блоков.
 
Поэтому я юзаю данный метод лишь для замены однотипных блоков.
Оно так же не подходит для чанков, которые уже были отправлены клиенту, тк оно обходит трекер изменений
 
Назад
Сверху