Structure Layout Optimizer
Попытки оптимизировать генерацию Jigsaw-структур и NBT-фрагментов
- Загрузчики
- FabricNeoForgeForge
- Скачиваний на Modrinth
- 8,6 млн
- Подписчиков на Modrinth
- 394
- версий
- 89
- Обновлён
- 16 сентября 202616 сент.
- Опубликован
- в 2024
Коротко о моде
Ставится только на сервер; игрокам ставить не нужно
Оптимизирует генерацию структур Jigsaw общего назначения настолько, насколько это возможно. По сути, этот мод не меняет внешний вид структур. Он лишь старается сделать генерацию структур быстрее и эффективнее. Вот и всё.
Вот более технические подробности выполненных оптимизаций. Пожалуйста, сообщайте о любых конфликтах или проблемах, обнаруженных при использовании этого мода в ваших сборках!
Заменяет неоптимизированные вызовы VertexShape на BoxOctree, чтобы части проверяли пересечения только с соседними частями, а не со всей структурой.
- По умолчанию vanilla использует VoxelShape для хранения границ частей, которые он собирает для разметки структуры. Когда он добавляет новую часть, ему нужно проверить, поместится ли она в разметку без пересечения с другими частями.
Проблема в том, что VoxelShape плохо подходит для этой цели: при проверке пересечения одного VoxelShape с другим сравниваются ВСЕ вершины. В структурах Jigsaw с множеством частей эта проверка пересечений замедляется тем сильнее, чем больше допустимых частей добавлено в разметку. Может вызывать лаг-спайк при генерации большого числа частей для рекурсивных структур Jigsaw.
Оптимизация здесь заменяет обычный VoxelShape на фиктивный VoxelShape, внутри которого хранится реализация BoxOctree, чтобы передавать BoxOctree туда, куда нужно. Этот BoxOctree при проверке пересечений проверяет только соседние части для входящей ограничивающей рамки. Таким образом предотвращается лавинообразный рост времени проверки пересечений, поскольку он игнорирует большинство частей, так как они слишком далеко, чтобы иметь значение для проверки.
- По умолчанию vanilla использует VoxelShape для хранения границ частей, которые он собирает для разметки структуры. Когда он добавляет новую часть, ему нужно проверить, поместится ли она в разметку без пересечения с другими частями.
Проверяет, полностью ли заблокирован Jigsaw Block, чтобы знать, когда пропускать проверку дочерних rigid-частей.
- В vanilla каждый Jigsaw Block в родительской части проверяет каждый Jigsaw Block в дочерней части, чтобы понять, когда пытаться соединить две части. Проблема в том, что если Jigsaw Block родительской части обращён к краю границы структуры ИЛИ обращён к другой отдельной части, то у этого Jigsaw Block нет места, чтобы когда-либо породить rigid-часть структуры. Поэтому мы можем сказать игре пропустить проверку этой rigid-дочерней части и вместо этого проверить следующую часть. Это избавляет нас от множества дорогостоящих проверок совпадений Jigsaw Block. Особенно в структурах с огромным количеством Jigsaw Block.
(26.2 и ниже) Заменяет сопоставление target/facing у Jigsaw на слегка более оптимизированную версию.
- Вдвое сокращает количество обращений к свойствам блоков. Vanilla дважды вызывает getValue для каждого JigsawBlock, чтобы получить значения top и front из одного и того же свойства, хотя можно было бы получить его один раз и извлечь все нужные значения. Также немного улучшена скорость получения значений joints, targets и строки name из NBT Jigsaw Block.
Кроме того, упрощена проверка данных joint, чтобы не требовалось преобразование в Enum через byName (непроизводительно), и переупорядочены проверки, чтобы сократить объём логики, которая должна выполняться часто.
Это поможет со структурами Jigsaw, в которых очень много Jigsaw Block, так как каждый Jigsaw Block прогоняется через этот код сопоставления для всех Jigsaw Block в других частях структуры.
- Вдвое сокращает количество обращений к свойствам блоков. Vanilla дважды вызывает getValue для каждого JigsawBlock, чтобы получить значения top и front из одного и того же свойства, хотя можно было бы получить его один раз и извлечь все нужные значения. Также немного улучшена скорость получения значений joints, targets и строки name из NBT Jigsaw Block.
Любой гигантский NBT структуры, у которого нет finalizeProcessing StructureProcessor, теперь загружается намного быстрее.
- Когда NBT-часть структуры генерируется в чанке, ВСЯ NBT-часть загружается в память, а затем несколько раз перебираются все позиции для применения StructureProcessor, после чего все позиции за пределами текущего генерируемого чанка игнорируются. Это не очень эффективно (по-настоящему расточительно) и вызывает долгую загрузку огромных NBT-файлов.
Оптимизация этого мода работает так: проверка границ выполняется заранее, чтобы отсеять все позиции, которые нам не нужны, прежде чем передавать их в StructureProcessor. Однако любой StructureProcessor, переопределяющий метод finalizeProcessing, может требовать все NBT-позиции для корректной работы, поэтому эта оптимизация отключается для любых частей с такими StructureProcessor, а таких структур будет очень мало. В vanilla только Trail Ruins не получит эту оптимизацию из-за использования Capped StructureProcessor, который переопределяет метод finalizeProcessing.
- Когда NBT-часть структуры генерируется в чанке, ВСЯ NBT-часть загружается в память, а затем несколько раз перебираются все позиции для применения StructureProcessor, после чего все позиции за пределами текущего генерируемого чанка игнорируются. Это не очень эффективно (по-настоящему расточительно) и вызывает долгую загрузку огромных NBT-файлов.
(1.21.1+) Заменил логику перемешивания и приоритизации списка Jigsaw Block в SinglePoolElement на чуть более быструю версию.
- Основная выгода — чуть более быстрый захват данных
selection_priorityиз NBT за счёт нового метода, который берёт запись один раз вместо двух. Vanilla делает это дважды, чтобы сначала проверить тип данных перед возвратом значения. Немного странно и расточительно.
Также попробовал новую систему сортировки для приоритизации, но она помогает лишь немногим структурам, которые реально используютselection_priority, вроде Trials Chamber. В целом это, вероятно, самая слабая оптимизация, но она довольно сильно помогает структурам Jigsaw с абсолютно нелепым количеством Jigsaw Block. Так что её стоит оставить.
Может нарушить паритет с vanilla-сидами в плане порядка, в котором запускаются Jigsaw Block, но пока я не нашёл этому подтверждений.
- Основная выгода — чуть более быстрый захват данных
Пропуск логики для SinglePoolElement, которые мы уже проверили и не смогли заспавнить в текущем месте.
Эта оптимизация исходит из того, что vanilla StructureTemplatePool хранит список всех SinglePoolElement с дубликатами элементов на основе их значения веса. Так что если в Template Pool вы укажете вес 100 для дома, этот дом будет добавлен в список 100 раз! И при генерации layout игра сделает копию этого списка, перемешает её и пройдётся по списку, пытаясь заспавнить первую подходящую часть. Это значит, что она будет заново прогонять проверочную логику для дубликатов в этом списке, даже если ранее выяснилось, что они не подходят для этого места. Моя оптимизация пропускает логику для частей, которые мы уже проверяли, и переходит к следующей части в списке. Это даёт хороший прирост производительности для структур, использующих много высоких значений веса в своих Template Pools.
Более того, вы можете включить опцию конфига
deduplicateShuffledTemplatePoolElementList, чтобы получить ещё больше производительности от элементов с высоким весом в Template Pools. Проблема в том, что эта опция идёт ценой изменения layout структуры. Layout всё ещё валидный и хороший. Он просто будет отличаться от того, каким был бы при выключенной опции конфига. По сути, это нарушает паритет сидов для layout структур специально ради дополнительного прироста производительности.- Чтобы было ясно, паритет сидов — это когда каждый раз при использовании сида 777 и наличии деревни в месте с 2 домами кузнеца каждый раз при использовании того же сида эта деревня остаётся на том же месте с двумя домами кузнеца. С включённой опцией оптимизации и тем же сидом эта деревня всё ещё будет на том же месте. Но в этот раз у неё может быть 1 дом кузнеца. И каждый раз при использовании того же сида с включённой опцией деревня будет продолжать генерироваться с 1 домом кузнеца. Layout стабилен для сида. Но он больше не такой же, как при выключенной опции.
(1.21.4 с v1.1.0+): Замена списка объектов StructureBlockInfo в StructureTemplate$Palette на палитру объектов StructureBlockInfo для снижения потребления памяти, когда этот кэшированный StructureTemplate не генерируется.
Эта оптимизация — модифицированная форма из мода Glacier от contaria для 1.16.1. Особая благодарность им за разрешение использовать их код как основу для этой оптимизации!
- По сути, в vanilla каждый раз при загрузке nbt-файла структуры он преобразуется в объект StructureTemplate и кэшируется. Внутри этого объекта спрятан список ВСЕХ позиций из этого nbt-файла вместе с блоками и nbt-тегом в каждой позиции. Это главный пожиратель памяти для объектов StructureTemplate. Этот мод заменит этот список специальным объектом структуры данных палитры под капотом, который притворяется списком. Размер палитры в памяти значительно меньше, чем у списка! Затем при запросе для worldgen он снова построит список как WeakReference, чтобы worldgen оставался быстрым и работал правильно. А когда worldgen завершится, этот список будет собран сборщиком мусора, чтобы снова освободить память, позволяя каждому StructureTemplate использовать полный объём памяти только при выполнении worldgen, но долгосрочно оставаться в кэше в меньшей форме. Минус в том, что этот список нельзя и не следует изменять вызовами add, remove, clear — это выбросит исключение. К счастью, я не думаю, что какой-либо мод изменяет этот список напрямую в StructureTemplate, но если да, пожалуйста, дайте мне знать.
- У ModernFix есть миксин, который делает сами объекты StructureTemplate SoftReference и полностью удаляет их из памяти, когда игра заполняет память. Это рабочее решение, направленное на остановку утечки памяти, вызванной загрузкой nbt структур в кэш, который никогда не очищается при длительной игре. Минус в том, что часть приходится снова загружать напрямую из файла, если она была удалена из памяти. Этот миксин отлично работает вместе с оптимизацией моего мода. Скорее всего, мой мод уменьшит размер StructureTemplate в памяти, что позволит ModernFix держать больше StructureTemplate в памяти, не удаляя их полностью. Что должно обеспечить больше попаданий в кэш в долгосрочной перспективе. В теории.
Частые вопросы
Как установить Structure Layout Optimizer?
Установите Fabric под свою версию Minecraft, скачайте Structure Layout Optimizer под ту же версию и загрузчик, положите файл в папку mods и запустите игру с профилем загрузчика.
Для каких версий Minecraft есть Structure Layout Optimizer?
У Structure Layout Optimizer есть сборки для Minecraft 1.19.2, 1.20.1, 1.21–1.21.1, 1.21.4–26.3 ….
Нужен ли Structure Layout Optimizer на сервере?
Ставится только на сервер; игрокам ставить не нужно