mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
276 lines
18 KiB
Diff
276 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
|
|
|
|
|
|
diff --git a/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java b/net/minecraft/world/level/levelgen/structure/pools/JigsawPlacement.java
|
|
index 63143ceec98f7a84ec4064d05e8f88c11200172f..02f67af9c312f3d9213af1e410986165dcf618a4 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;
|
|
@@ -292,6 +294,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.DivineConfig.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.DivineConfig.enableStructureLayoutOptimizer || !org.bxteam.divinemc.DivineConfig.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.DivineConfig.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.DivineConfig.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.DivineConfig.enableStructureLayoutOptimizer) {
|
|
+ return original;
|
|
+ }
|
|
+ if (!org.bxteam.divinemc.DivineConfig.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,
|
|
@@ -349,9 +453,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));
|
|
@@ -362,10 +466,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) {
|
|
@@ -398,7 +506,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);
|
|
@@ -427,9 +535,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.DivineConfig.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 4a6da3648c513a6cce16cf71246937d2d0ad014d..6af4c9026e814dee1ed4c7593ad00b5f8af9b979 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.DivineConfig.enableStructureLayoutOptimizer) {
|
|
+ structureLayoutOptimizer$fasterJigsawListShuffling1(jigsaws, random);
|
|
+ structureLayoutOptimizer$fasterJigsawListShuffling2(jigsaws);
|
|
+ } else {
|
|
+ Util.shuffle(jigsaws, random);
|
|
+ sortBySelectionPriority(jigsaws);
|
|
+ }
|
|
+ // DivineMC end - Optimize Structure Generation
|
|
+
|
|
return jigsaws;
|
|
}
|
|
|
|
@@ -191,4 +199,12 @@ public class SinglePoolElement extends StructurePoolElement {
|
|
public String toString() {
|
|
return "Single[" + this.template + "]";
|
|
}
|
|
+
|
|
+ // 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) { }
|
|
+ // Quiil 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 a37eb2e29b4577ebc711e8ef7b47fbbc3bc66897..45d6fbeeaac577bb35adb69fd344b9486953ea03 100644
|
|
--- a/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
|
|
+++ b/net/minecraft/world/level/levelgen/structure/templatesystem/StructureTemplate.java
|
|
@@ -249,6 +249,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;
|
|
@@ -266,7 +272,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.DivineConfig.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
|
|
@@ -890,7 +900,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.DivineConfig.enableStructureLayoutOptimizer
|
|
+ ? new org.bxteam.divinemc.util.structure.PalettedStructureBlockInfoList(blocks)
|
|
+ : blocks;
|
|
+ // DivineMC end - Optimize Structure Generation
|
|
}
|
|
|
|
public List<StructureTemplate.JigsawBlockInfo> jigsaws() {
|