9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-19 14:59:25 +00:00
Files
DivineMC/divinemc-server/minecraft-patches/features/0034-Optimize-Structure-Generation.patch
2025-10-01 01:38:10 +03:00

278 lines
18 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Tue, 4 Feb 2025 19:52:24 +0300
Subject: [PATCH] Optimize Structure Generation
Original project: https://github.com/TelepathicGrunt/StructureLayoutOptimizer
Original license: MIT
diff --git a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
index 1cfa0fcd28685736fcdce4aef817e4d4cc4061cb..cd3b24a760053dcd650a1a263b3c0093a0cbb175 100644
--- a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
+++ b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
@@ -4,6 +4,8 @@ import com.google.common.collect.Lists;
import com.mojang.logging.LogUtils;
import java.util.List;
import java.util.Optional;
+import java.util.ArrayList;
+import java.util.LinkedHashSet;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
@@ -288,6 +290,108 @@ public class JigsawPlacement {
this.random = random;
}
+ // DivineMC start - Optimize Structure Generation
+ private boolean structureLayoutOptimizer$optimizeJigsawConnecting(StructureTemplate.JigsawBlockInfo jigsaw1, StructureTemplate.JigsawBlockInfo jigsaw2) {
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
+ return JigsawBlock.canAttach(jigsaw1, jigsaw2);
+ }
+ return org.bxteam.divinemc.util.structure.GeneralUtils.canJigsawsAttach(jigsaw1, jigsaw2);
+ }
+
+ private void structureLayoutOptimizer$replaceVoxelShape3(MutableObject<VoxelShape> instance, BoundingBox pieceBounds) {
+ org.bxteam.divinemc.util.structure.TrojanVoxelShape trojanVoxelShape = new org.bxteam.divinemc.util.structure.TrojanVoxelShape(new org.bxteam.divinemc.util.structure.BoxOctree(AABB.of(pieceBounds)));
+ instance.setValue(trojanVoxelShape);
+ }
+
+ private void structureLayoutOptimizer$replaceVoxelShape4(MutableObject<VoxelShape> instance, BoundingBox pieceBounds) {
+ if (instance.getValue() instanceof org.bxteam.divinemc.util.structure.TrojanVoxelShape trojanVoxelShape) {
+ trojanVoxelShape.boxOctree.addBox(AABB.of(pieceBounds));
+ }
+ }
+
+ private List<StructurePoolElement> structureLayoutOptimizer$removeDuplicateTemplatePoolElementLists(StructureTemplatePool instance, RandomSource random) {
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer || !org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.deduplicateShuffledTemplatePoolElementList) {
+ return instance.getShuffledTemplates(random);
+ }
+
+ // Linked hashset keeps order of elements.
+ LinkedHashSet<StructurePoolElement> uniquePieces = new LinkedHashSet<>((instance).rawTemplates.size());
+
+ // Don't use addAll. Want to keep it simple in case of inefficiency in collection's addAll.
+ // Set will ignore duplicates after first appearance of an element.
+ for (StructurePoolElement piece : instance.getShuffledTemplates(random)) {
+ //noinspection UseBulkOperation
+ uniquePieces.add(piece);
+ }
+
+ // Move the elements from set to the list in the same order.
+ int uniquePiecesFound = uniquePieces.size();
+ List<StructurePoolElement> deduplicatedListOfPieces = new ArrayList<>(uniquePiecesFound);
+ for (int i = 0; i < uniquePiecesFound; i++) {
+ deduplicatedListOfPieces.add(uniquePieces.removeFirst());
+ }
+
+ return deduplicatedListOfPieces;
+ }
+
+ private ArrayList<StructurePoolElement> structureLayoutOptimizer$skipDuplicateTemplatePoolElementLists1() {
+ // Swap with trojan list, so we can record what pieces we visited
+ return org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.deduplicateShuffledTemplatePoolElementList ? Lists.newArrayList() : new org.bxteam.divinemc.util.structure.TrojanArrayList<>();
+ }
+
+ private List structureLayoutOptimizer$skipBlockedJigsaws(
+ List original,
+ boolean useExpansionHack,
+ MutableObject<VoxelShape> voxelShapeMutableObject,
+ StructurePoolElement structurePoolElement,
+ StructureTemplate.StructureBlockInfo parentJigsawBlockInfo,
+ BlockPos parentTargetPosition)
+ {
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
+ return original;
+ }
+ if (voxelShapeMutableObject.getValue() instanceof org.bxteam.divinemc.util.structure.TrojanVoxelShape trojanVoxelShape) {
+ // If rigid and target position is already an invalid spot, do not run rest of logic.
+ StructureTemplatePool.Projection candidatePlacementBehavior = structurePoolElement.getProjection();
+ boolean isCandidateRigid = candidatePlacementBehavior == StructureTemplatePool.Projection.RIGID;
+ if (isCandidateRigid && (!trojanVoxelShape.boxOctree.boundaryContains(parentTargetPosition) || trojanVoxelShape.boxOctree.withinAnyBox(parentTargetPosition))) {
+ return new ArrayList<>();
+ }
+ }
+ return original;
+ }
+
+ private List<Rotation> structureLayoutOptimizer$skipDuplicateTemplatePoolElementLists2(List<Rotation> original,
+ List<StructurePoolElement> list,
+ StructurePoolElement structurepoolelement1)
+ {
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
+ return original;
+ }
+ if (!org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.deduplicateShuffledTemplatePoolElementList && list instanceof org.bxteam.divinemc.util.structure.TrojanArrayList<net.minecraft.world.level.levelgen.structure.pools.StructurePoolElement> trojanArrayList) {
+ // Do not run this piece's logic since we already checked its 4 rotations in the past.
+ if (trojanArrayList.elementsAlreadyParsed.contains(structurepoolelement1)) {
+
+ // Prime the random with the random calls we would've skipped.
+ // Maintains vanilla compat.
+ for (Rotation rotation1 : original) {
+ structurepoolelement1.getShuffledJigsawBlocks(this.structureTemplateManager, BlockPos.ZERO, rotation1, this.random);
+ }
+
+ // Short circuit the Rotation loop
+ return new ArrayList<>();
+ }
+ // Record piece as it will go through the 4 rotation checks for spawning.
+ else {
+ trojanArrayList.elementsAlreadyParsed.add(structurepoolelement1);
+ }
+ }
+
+ // Allow the vanilla code to run normally.
+ return original;
+ }
+ // DivineMC end - Optimize Structure Generation
+
void tryPlacingChildren(
PoolElementStructurePiece piece,
MutableObject<VoxelShape> free,
@@ -345,9 +449,9 @@ public class JigsawPlacement {
mutableObject1 = free;
}
- List<StructurePoolElement> list = Lists.newArrayList();
+ List<StructurePoolElement> list = structureLayoutOptimizer$skipDuplicateTemplatePoolElementLists1(); // DivineMC - Optimize Structure Generation
if (depth != this.maxDepth) {
- list.addAll(holder.value().getShuffledTemplates(this.random));
+ list.addAll(structureLayoutOptimizer$removeDuplicateTemplatePoolElementLists(holder.value(), this.random)); // DivineMC - Optimize Structure Generation
}
list.addAll(fallback.value().getShuffledTemplates(this.random));
@@ -358,10 +462,14 @@ public class JigsawPlacement {
break;
}
- for (Rotation rotation1 : Rotation.getShuffled(this.random)) {
- List<StructureTemplate.JigsawBlockInfo> shuffledJigsawBlocks = structurePoolElement.getShuffledJigsawBlocks(
+ // DivineMC start - Optimize Structure Generation
+ for (Rotation rotation1 : structureLayoutOptimizer$skipDuplicateTemplatePoolElementLists2(Rotation.getShuffled(this.random), list, structurePoolElement)) {
+ List<StructureTemplate.JigsawBlockInfo> shuffledJigsawBlocks = structureLayoutOptimizer$skipBlockedJigsaws(
+ structurePoolElement.getShuffledJigsawBlocks(
this.structureTemplateManager, BlockPos.ZERO, rotation1, this.random
+ ), useExpansionHack, mutableObject1, structurePoolElement, structureBlockInfo, blockPos1
);
+ // DivineMC end - Optimize Structure Generation
BoundingBox boundingBox1 = structurePoolElement.getBoundingBox(this.structureTemplateManager, BlockPos.ZERO, rotation1);
int i2;
if (useExpansionHack && boundingBox1.getYSpan() <= 16) {
@@ -394,7 +502,7 @@ public class JigsawPlacement {
}
for (StructureTemplate.JigsawBlockInfo jigsawBlockInfo1 : shuffledJigsawBlocks) {
- if (JigsawBlock.canAttach(jigsawBlockInfo, jigsawBlockInfo1)) {
+ if (structureLayoutOptimizer$optimizeJigsawConnecting(jigsawBlockInfo, jigsawBlockInfo1)) { // DivineMC - Optimize Structure Generation
BlockPos blockPos2 = jigsawBlockInfo1.info().pos();
BlockPos blockPos3 = blockPos1.subtract(blockPos2);
BoundingBox boundingBox2 = structurePoolElement.getBoundingBox(this.structureTemplateManager, blockPos3, rotation1);
@@ -423,9 +531,26 @@ public class JigsawPlacement {
boundingBox3.encapsulate(new BlockPos(boundingBox3.minX(), boundingBox3.minY() + max, boundingBox3.minZ()));
}
- if (!Shapes.joinIsNotEmpty(
- mutableObject1.getValue(), Shapes.create(AABB.of(boundingBox3).deflate(0.25)), BooleanOp.ONLY_SECOND
- )) {
+ // DivineMC start - Optimize Structure Generation
+ boolean internal$joinIsNotEmpty;
+ VoxelShape parentBounds = mutableObject1.getValue();
+ java.util.function.Supplier<Boolean> original = () -> Shapes.joinIsNotEmpty(
+ parentBounds, Shapes.create(AABB.of(boundingBox3).deflate(0.25)), BooleanOp.ONLY_SECOND
+ );
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
+ if (parentBounds instanceof org.bxteam.divinemc.util.structure.TrojanVoxelShape trojanVoxelShape) {
+ AABB pieceAABB = AABB.of(boundingBox3).deflate(0.25D);
+
+ // Have to inverse because of an ! outside our wrap
+ internal$joinIsNotEmpty = !trojanVoxelShape.boxOctree.withinBoundsButNotIntersectingChildren(pieceAABB);
+ } else {
+ internal$joinIsNotEmpty = original.get();
+ }
+ } else {
+ internal$joinIsNotEmpty = original.get();
+ }
+ if (!internal$joinIsNotEmpty) {
+ // DivineMC end - Optimize Structure Generation
mutableObject1.setValue(
Shapes.joinUnoptimized(
mutableObject1.getValue(), Shapes.create(AABB.of(boundingBox3)), BooleanOp.ONLY_FIRST
diff --git a/net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement.java b/net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement.java
index 5c081a5b3d10f713e4e82fe1a43758f553fe50e0..85e84603a19964f05d9d5e62eb096ca76c36ab00 100644
--- a/net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement.java
+++ b/net/minecraft/world/level/levelgen/structure/pools/SinglePoolElement.java
@@ -119,8 +119,16 @@ public class SinglePoolElement extends StructurePoolElement {
StructureTemplateManager structureTemplateManager, BlockPos pos, Rotation rotation, RandomSource random
) {
List<StructureTemplate.JigsawBlockInfo> jigsaws = this.getTemplate(structureTemplateManager).getJigsaws(pos, rotation);
- Util.shuffle(jigsaws, random);
- sortBySelectionPriority(jigsaws);
+ // DivineMC start - Optimize Structure Generation
+ if (org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer) {
+ structureLayoutOptimizer$fasterJigsawListShuffling1(jigsaws, random);
+ structureLayoutOptimizer$fasterJigsawListShuffling2(jigsaws);
+ } else {
+ Util.shuffle(jigsaws, random);
+ sortBySelectionPriority(jigsaws);
+ }
+ // DivineMC end - Optimize Structure Generation
+
return jigsaws;
}
@@ -196,4 +204,12 @@ public class SinglePoolElement extends StructurePoolElement {
public ResourceLocation getTemplateLocation() {
return this.template.orThrow();
}
+
+ // DivineMC start - Optimize Structure Generation
+ private void structureLayoutOptimizer$fasterJigsawListShuffling1(List<StructureTemplate.JigsawBlockInfo> list, RandomSource randomSource) {
+ org.bxteam.divinemc.util.structure.GeneralUtils.shuffleAndPrioritize(list, randomSource);
+ }
+
+ private void structureLayoutOptimizer$fasterJigsawListShuffling2(List<StructureTemplate.JigsawBlockInfo> structureBlockInfos) { }
+ // DivineMC end - Optimize Structure Generation
}
diff --git a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
index f21e612a35d6ac4482dbf5d14e506959659e371a..c02c3b1fddd513cb477cbb7400c30a9ad57f80a6 100644
--- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
@@ -255,6 +255,12 @@ public class StructureTemplate {
return transform(pos, decorator.getMirror(), decorator.getRotation(), decorator.getRotationPivot());
}
+ // DivineMC start - Optimize Structure Generation
+ private List<StructureTemplate.StructureBlockInfo> structureLayoutOptimizer$shrinkStructureTemplateBlocksList(StructureTemplate.Palette palette, BlockPos offset, StructurePlaceSettings settings) {
+ return org.bxteam.divinemc.util.structure.StructureTemplateOptimizer.getStructureBlockInfosInBounds(palette, offset, settings);
+ }
+ // DivineMC end - Optimize Structure Generation
+
public boolean placeInWorld(ServerLevelAccessor serverLevel, BlockPos offset, BlockPos pos, StructurePlaceSettings settings, RandomSource random, int flags) {
if (this.palettes.isEmpty()) {
return false;
@@ -272,7 +278,11 @@ public class StructureTemplate {
}
}
// CraftBukkit end
- List<StructureTemplate.StructureBlockInfo> list = settings.getRandomPalette(this.palettes, offset).blocks();
+ // DivineMC start - Optimize Structure Generation
+ List<StructureTemplate.StructureBlockInfo> list = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer
+ ? structureLayoutOptimizer$shrinkStructureTemplateBlocksList(settings.getRandomPalette(this.palettes, offset), offset, settings)
+ : settings.getRandomPalette(this.palettes, offset).blocks();
+ // DivineMC end - Optimize Structure Generation
if ((!list.isEmpty() || !settings.isIgnoreEntities() && !this.entityInfoList.isEmpty())
&& this.size.getX() >= 1
&& this.size.getY() >= 1
@@ -882,7 +892,11 @@ public class StructureTemplate {
private List<StructureTemplate.JigsawBlockInfo> cachedJigsaws;
Palette(List<StructureTemplate.StructureBlockInfo> blocks) {
- this.blocks = blocks;
+ // DivineMC start - Optimize Structure Generation
+ this.blocks = org.bxteam.divinemc.config.DivineConfig.PerformanceCategory.enableStructureLayoutOptimizer
+ ? new org.bxteam.divinemc.util.structure.PalettedStructureBlockInfoList(blocks)
+ : blocks;
+ // DivineMC end - Optimize Structure Generation
}
public List<StructureTemplate.JigsawBlockInfo> jigsaws() {