mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
278 lines
18 KiB
Diff
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() {
|