Attempts to optimize the generation of Jigsaw Structures and NBT pieces
Optimizes general Jigsaw structure generation as best I can. Essentially this mod aims to not change how structures look at all. It only works to try and make structures generate faster and more efficiently. That's it.
Here are the more technical details of the optimizations done. Please report any conflicts or issues that is discovered when running this mod in your modpacks!
Replaces VertexShape unoptimized calls with a BoxOctree to make pieces only check nearby pieces for intersections instead of entire structure.
Check if a Jigsaw Block is blocked off entirely to know when to skip checking child rigid pieces.
Replaces Jigsaw target/facing match up with a slightly more optimized version.
Made any giant structure NBT that has no finalizeProcessing StructureProcessor now load much faster.
(1.21.1+) Replaced the Jigsaw Block list shuffling and prioritization logic in SinglePoolElement with a slightly faster version.
selection_priority data grabbing from NBT by using a new method that grabs the entry once instead of twice. Vanilla does it twice to check the data type first before returning the value. A bit odd and wasteful. selection_priority like Trials Chamber. Overall, this is probably the weakest optimization but it does quite a bit of help for Jigsaw structures that has an absolutely ridiculous amount of Jigsaw Blocks. So it is worth keeping this optimization. Skip running logic for SinglePoolElements we already checked and could not spawn at the current spot.
So this optimization comes from the fact that vanilla StructureTemplatePool holds a list of all the SinglePoolElements with duplicates of the elements based on their weight value. So if in a Template Pool, you specify weight 100 for a house, that house will be put into this list 100 times! And when generating the layout, the game will make a copy of this list, shuffle it, and iterate over the list to try and spawn the first piece it finds that fits. This means it will rerun the checking logic for duplicate entries in this list even if it was found to not fit before at the spot. The optimization I do is skip the logic for pieces we already checked before and continue to the next piece in the list. This gives a nice performance boost for structures that uses a lot of high weight values in their Template Pools.
Furthermore, you can turn on the deduplicateShuffledTemplatePoolElementList config option to get even more performance out of high weight elements in Template Pools. The issue is this config comes at a cost of changing the layout of the structure. The layout is still valid and good. It would just be different than if the config option is kept off. Basically it breaks seed parity for structure layouts specifically to get that extra performance boost.
*To be clear, seed parity is every time you use the seed 777 and there is a village at a spot with 2 blacksmith houses, every time you use that same seed, that village will remain at that spot with the two blacksmith houses. With this optimization config turned on and same seed, that village will still be at same spot. But it may have 1 blacksmith house this time. And every time you use the same seed with this config on, the village will continue to generate with the 1 blacksmith house. The layout is seed stable. But just no longer is the same as if the config is turned off.
(1.21.4 with v1.1.0+): Swap StructureTemplate$Palette's list of StructureBlockInfo objects to be a palette of StructureBlockInfo objects instead for reduced memory usage when not generating that cached StructureTemplate.
This optimization is a modified form from contaria's Glacier mod for 1.16.1. Special thanks to them for allowing me to use their code as a basis for this optimization!
Essentially in vanilla, every time a structure nbt file is loaded, it is converted to a StructureTemplate object and cached. Buried in that object is a list of ALL the positions from that nbt file paired with the blocks and nbt tag at each position. This is the biggest memory hog for StructureTemplate objects. What this mod will do is swap this list with a special palette data structure object under the hood that pretends to be a list. The memory size of the palette is significantly smaller than the list! Then when queried for worldgen, it will construct the list again as a WeakReference so worldgen remains fast and works properly. And when worldgen is done, this list will get garbage collected to free up memory again, allowing each StructureTemplate to only use the full amount of memory they need when doing worldgen but stay cached in a smaller form long term. The downside is this list cannot and should not be modified with add, remove, clear calls and will throw and exception if done. Luckily, I do not think any mod is modifying this list itself on StructureTemplate directly but if they do, please let me know.
ModernFix does have a mixin that will make the StructureTemplate objects themselves be a SoftReference and be removed completely from memory when the game gets full on memory. This is a valid solution and aims to stop the memory leak of loading structure nbts into a cache that never clears in long term gameplay. The downside of this is that the piece has to be loaded directly from the file again if it was cleared from memory. This mixin will work just fine alongside my mod's optimization. What will probably happen is my mod make StructureTemplate smaller in memory which allows ModernFix to keep more StructureTemplates in memory without them getting fully removed from memory. Which should allow more cache hits over long term. In theory.
Conversation