diff --git a/src/main/java/twilightforest/ASMHooks.java b/src/main/java/twilightforest/ASMHooks.java
index 2fe8ad7fe4..b4e3afe35e 100644
--- a/src/main/java/twilightforest/ASMHooks.java
+++ b/src/main/java/twilightforest/ASMHooks.java
@@ -26,6 +26,7 @@
import net.minecraft.world.item.*;
import net.minecraft.world.level.*;
import net.minecraft.world.level.biome.Biome;
+import net.minecraft.world.level.biome.BiomeResolver;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
@@ -51,6 +52,7 @@
import twilightforest.init.TFDataComponents;
import twilightforest.init.custom.ChunkBlanketProcessors;
import twilightforest.util.WorldUtil;
+import twilightforest.world.components.biomesources.TFBiomeProvider;
import twilightforest.world.components.structures.CustomDensitySource;
import twilightforest.world.components.structures.util.CustomStructureData;
@@ -166,6 +168,20 @@ public static void chunkBlanketing(ChunkAccess chunkAccess, WorldGenRegion world
ChunkBlanketProcessors.chunkBlanketing(chunkAccess, worldGenRegion);
}
+ /**
+ * {@link twilightforest.asm.transformers.chunk.NoiseBasedChunkGeneratorTransformer}
+ *
+ * Injection Point:
+ * {@link net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator#doCreateBiomes}
+ */
+ public static BiomeResolver tryRecreateBiomeResolver(BiomeResolver resolver) {
+ if (resolver instanceof TFBiomeProvider tfBiomeProvider) {
+ return tfBiomeProvider.recreate();
+ } else {
+ return resolver;
+ }
+ }
+
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cloud
// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/main/java/twilightforest/world/components/biomesources/TFBiomeProvider.java b/src/main/java/twilightforest/world/components/biomesources/TFBiomeProvider.java
index 631dc2ed4b..eb9d441bbf 100644
--- a/src/main/java/twilightforest/world/components/biomesources/TFBiomeProvider.java
+++ b/src/main/java/twilightforest/world/components/biomesources/TFBiomeProvider.java
@@ -52,6 +52,10 @@ public BiomeDensitySource getBiomeTerrain() {
return this.biomeTerrainDataHolder.value();
}
+ public TFBiomeProvider recreate() {
+ return new TFBiomeProvider(new Holder.Direct<>(this.biomeTerrainDataHolder.value().recreate()));
+ }
+
@Override
public void addDebugInfo(List info, BlockPos cameraPos, Climate.Sampler sampler) {
super.addDebugInfo(info, cameraPos, sampler);
diff --git a/src/main/java/twilightforest/world/components/chunkgenerators/TerrainDensityRouter.java b/src/main/java/twilightforest/world/components/chunkgenerators/TerrainDensityRouter.java
index e2b8152170..64299f5eaa 100644
--- a/src/main/java/twilightforest/world/components/chunkgenerators/TerrainDensityRouter.java
+++ b/src/main/java/twilightforest/world/components/chunkgenerators/TerrainDensityRouter.java
@@ -122,7 +122,7 @@ public DensityFunction baseOffset() {
@Override // NoiseChunk is the only class to ever call this, and it's typically a new chunk each time
public DensityFunction mapAll(Visitor visitor) {
return visitor.apply(new ChunkCachedDensityRouter(
- this.biomeDensitySourceHolder,
+ new Holder.Direct<>(this.biomeDensitySourceHolder.value().recreate()), // isolate LazyArea cache between chunks
visitor.visitNoise(this.noise),
this.lowerDensityBound,
this.upperDensityBound,
diff --git a/src/main/java/twilightforest/world/components/feature/trees/CanopyMushroomFeature.java b/src/main/java/twilightforest/world/components/feature/trees/CanopyMushroomFeature.java
index 7f328dca64..b1346e8377 100644
--- a/src/main/java/twilightforest/world/components/feature/trees/CanopyMushroomFeature.java
+++ b/src/main/java/twilightforest/world/components/feature/trees/CanopyMushroomFeature.java
@@ -5,12 +5,14 @@
import net.minecraft.core.Direction;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.LevelAccessor;
+import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.DirectionalBlock;
import net.minecraft.world.level.block.HugeMushroomBlock;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.levelgen.feature.AbstractHugeMushroomFeature;
import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
import net.minecraft.world.level.levelgen.feature.configurations.HugeMushroomFeatureConfiguration;
+import org.apache.commons.lang3.mutable.MutableInt;
import twilightforest.init.TFBlocks;
import twilightforest.util.features.FeatureLogic;
import twilightforest.util.iterators.VoxelBresenhamIterator;
@@ -19,8 +21,6 @@
@ParametersAreNonnullByDefault
public abstract class CanopyMushroomFeature extends AbstractHugeMushroomFeature {
- private int bugsLeft;
-
public CanopyMushroomFeature(Codec featureConfigurationCodec) {
super(featureConfigurationCodec);
}
@@ -35,12 +35,16 @@ protected int getTreeRadiusForHeight(int i, int i1, int foliageRadius, int treeH
@Override
protected void placeTrunk(LevelAccessor levelAccessor, RandomSource random, BlockPos pos, HugeMushroomFeatureConfiguration featureConfiguration, int height, BlockPos.MutableBlockPos mutableBlockPos) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected void placeTrunk(LevelAccessor levelAccessor, RandomSource random, BlockPos pos, HugeMushroomFeatureConfiguration featureConfiguration, int height, BlockPos.MutableBlockPos mutableBlockPos, MutableInt bugsLeft) {
for (int i = 0; i < height; ++i) {
mutableBlockPos.set(pos).move(Direction.UP, i);
if (!levelAccessor.getBlockState(mutableBlockPos).isSolidRender(levelAccessor, mutableBlockPos)) {
this.setBlock(levelAccessor, mutableBlockPos, featureConfiguration.stemProvider.getState(random, pos));
- if (this.bugsLeft > 0 && i > height / 2 && random.nextInt(10) == 9) addFirefly(levelAccessor, mutableBlockPos, random);
+ if (bugsLeft.intValue() > 0 && i > height / 2 && random.nextInt(10) == 9) addFirefly(levelAccessor, mutableBlockPos, random, bugsLeft);
} else {
height = i;
break;
@@ -50,14 +54,14 @@ protected void placeTrunk(LevelAccessor levelAccessor, RandomSource random, Bloc
int numBranches = this.getBranches(random);
float offset = random.nextFloat();
for (int b = 0; b < numBranches; b++) {
- buildABranch(levelAccessor, pos, height - 6 + b, this.getLength(random), 0.3 * b + offset, random, new HugeMushroomFeatureConfiguration(featureConfiguration.capProvider, featureConfiguration.stemProvider, featureConfiguration.foliageRadius - 1));
+ buildABranch(levelAccessor, pos, height - 6 + b, this.getLength(random), 0.3 * b + offset, random, new HugeMushroomFeatureConfiguration(featureConfiguration.capProvider, featureConfiguration.stemProvider, featureConfiguration.foliageRadius - 1), bugsLeft);
}
}
/**
* Add a firefly on a RandomSource face of a block
*/
- protected void addFirefly(LevelAccessor levelAccessor, BlockPos pos, RandomSource random) {
+ protected void addFirefly(LevelAccessor levelAccessor, BlockPos pos, RandomSource random, MutableInt bugsLeft) {
Direction direction = Direction.getRandom(random);
if (direction.getAxis() != Direction.Axis.Y) {
BlockPos.MutableBlockPos bugPos = new BlockPos.MutableBlockPos();
@@ -65,7 +69,7 @@ protected void addFirefly(LevelAccessor levelAccessor, BlockPos pos, RandomSourc
if (!levelAccessor.getBlockState(bugPos).isSolidRender(levelAccessor, bugPos)) {
BlockState bugState = TFBlocks.FIREFLY.get().defaultBlockState().setValue(DirectionalBlock.FACING, direction);
this.setBlock(levelAccessor, bugPos, bugState);
- this.bugsLeft--;
+ bugsLeft.decrement();
}
}
}
@@ -79,7 +83,7 @@ protected int getTreeHeight(RandomSource random) {
protected abstract double getLength(RandomSource random);
- private void buildABranch(LevelAccessor levelAccessor, BlockPos pos, int height, double length, double angle, RandomSource random, HugeMushroomFeatureConfiguration featureConfiguration) {
+ private void buildABranch(LevelAccessor levelAccessor, BlockPos pos, int height, double length, double angle, RandomSource random, HugeMushroomFeatureConfiguration featureConfiguration, MutableInt bugsLeft) {
BlockPos src = pos.above(height);
BlockPos dest = FeatureLogic.translate(src, length, angle, 0.2);
@@ -106,7 +110,7 @@ private void buildABranch(LevelAccessor levelAccessor, BlockPos pos, int height,
this.setBlock(levelAccessor, blockPos, blockstate);
- if (this.bugsLeft > 0 && i > Math.min(src.getY(), dest.getY()) / 2 && random.nextInt(20) == 0) addFirefly(levelAccessor, blockPos, random);
+ if (bugsLeft.intValue() > 0 && i > Math.min(src.getY(), dest.getY()) / 2 && random.nextInt(20) == 0) addFirefly(levelAccessor, blockPos, random, bugsLeft);
}
this.makeCap(levelAccessor, random, dest, 1, new BlockPos.MutableBlockPos(), featureConfiguration);//Branches need caps as well, height in this case is set to 1
@@ -132,7 +136,21 @@ protected void makeCap(LevelAccessor levelAccessor, RandomSource random, BlockPo
@Override
public boolean place(FeaturePlaceContext context) {
- this.bugsLeft = Math.max(0, context.random().nextInt(10) - 4) / 2; //Weird math, I know, but I like the odds (and weird math, sue me)
- return super.place(context);
+ MutableInt bugsLeft = new MutableInt(Math.max(0, context.random().nextInt(10) - 4) / 2); //Weird math, I know, but I like the odds (and weird math, sue me)
+
+ // [VanillaCopy] AbstractHugeMushroomFeature.place, passing bugsLeft as parameter
+ WorldGenLevel worldgenlevel = context.level();
+ BlockPos blockpos = context.origin();
+ RandomSource randomsource = context.random();
+ HugeMushroomFeatureConfiguration hugemushroomfeatureconfiguration = context.config();
+ int i = this.getTreeHeight(randomsource);
+ BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos();
+ if (!this.isValidPosition(worldgenlevel, blockpos, i, blockpos$mutableblockpos, hugemushroomfeatureconfiguration)) {
+ return false;
+ } else {
+ this.makeCap(worldgenlevel, randomsource, blockpos, i, blockpos$mutableblockpos, hugemushroomfeatureconfiguration);
+ this.placeTrunk(worldgenlevel, randomsource, blockpos, hugemushroomfeatureconfiguration, i, blockpos$mutableblockpos, bugsLeft);
+ return true;
+ }
}
}
diff --git a/src/main/java/twilightforest/world/components/layer/BiomeDensitySource.java b/src/main/java/twilightforest/world/components/layer/BiomeDensitySource.java
index 39b3dcd428..40782eb427 100644
--- a/src/main/java/twilightforest/world/components/layer/BiomeDensitySource.java
+++ b/src/main/java/twilightforest/world/components/layer/BiomeDensitySource.java
@@ -51,6 +51,10 @@ public BiomeDensitySource(Map, TerrainColumn> list, Holder getBiomeConfig() {
return this.genBiomeConfig;
}
diff --git a/src/main/java/twilightforest/world/components/structures/TFMaze.java b/src/main/java/twilightforest/world/components/structures/TFMaze.java
index 94208ab069..d0e5cf0e71 100644
--- a/src/main/java/twilightforest/world/components/structures/TFMaze.java
+++ b/src/main/java/twilightforest/world/components/structures/TFMaze.java
@@ -24,7 +24,7 @@
*
* @author Ben
*/
-public class TFMaze {
+public class TFMaze implements Cloneable {
public final int width; // cells wide (x)
public final int depth; // cells deep (z)
@@ -63,7 +63,7 @@ public class TFMaze {
public static final int ROOM = 5;
public static final int DOOR = 6;
- public final RandomSource rand;
+ public RandomSource rand;
public TFMaze(int cellsWidth, int cellsDepth, RandomSource random) {
// default values
@@ -576,4 +576,15 @@ public void rbGen(int sx, int sz) {
rbGen(sx, sz);
rbGen(sx, sz);
}
+
+ @Override
+ public TFMaze clone() {
+ try {
+ TFMaze clone = (TFMaze) super.clone();
+ clone.rand = RandomSource.create();
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError();
+ }
+ }
}
diff --git a/src/main/java/twilightforest/world/components/structures/finalcastle/FinalCastleMuralComponent.java b/src/main/java/twilightforest/world/components/structures/finalcastle/FinalCastleMuralComponent.java
index 036b51994b..bcdb04d53d 100644
--- a/src/main/java/twilightforest/world/components/structures/finalcastle/FinalCastleMuralComponent.java
+++ b/src/main/java/twilightforest/world/components/structures/finalcastle/FinalCastleMuralComponent.java
@@ -22,7 +22,7 @@ public class FinalCastleMuralComponent extends TFStructureComponentOld {
private int width;
// we will model the mural in this byte array
- private byte[][] mural;
+ private volatile byte[][] mural;
public FinalCastleMuralComponent(StructurePieceSerializationContext ctx, CompoundTag nbt) {
super(TFStructurePieceTypes.TFFCMur.get(), nbt);
@@ -37,34 +37,40 @@ public FinalCastleMuralComponent(int i, int x, int y, int z, int width, int heig
@Override
public void postProcess(WorldGenLevel world, StructureManager manager, ChunkGenerator generator, RandomSource rand, BoundingBox sbb, ChunkPos chunkPosIn, BlockPos blockPos) {
- this.height = this.boundingBox.getYSpan();
- this.width = (this.getOrientation() == Direction.SOUTH || this.getOrientation() == Direction.NORTH) ? this.boundingBox.getZSpan() : this.boundingBox.getXSpan();
-
RandomSource decoRNG = RandomSource.create(world.getSeed() + (this.boundingBox.minX() * 321534781L) ^ (this.boundingBox.minZ() * 756839L));
- if (mural == null) {
- // only make it once
- mural = new byte[width][height];
+ if (this.mural == null) {
+ synchronized (this) {
+ if (this.mural == null) {
+ this.height = this.boundingBox.getYSpan();
+ this.width = (this.getOrientation() == Direction.SOUTH || this.getOrientation() == Direction.NORTH) ? this.boundingBox.getZSpan() : this.boundingBox.getXSpan();
- int startX = width / 2 - 1;
- int startY = 2;
+ // only make it once
+ byte[][] mural = new byte[width][height];
- // make mural, fill in dot by start
- for (int x = -1; x < 2; x++) {
- for (int y = -1; y < 2; y++) {
- mural[startX + x][startY + y] = 1;
- }
- }
+ int startX = width / 2 - 1;
+ int startY = 2;
- // side branches
- makeHorizontalTree(decoRNG, mural, startX + 1, startY, decoRNG.nextInt(width / 6) + width / 6, true);
- makeHorizontalTree(decoRNG, mural, startX - 1, startY, decoRNG.nextInt(width / 6) + width / 6, false);
+ // make mural, fill in dot by start
+ for (int x = -1; x < 2; x++) {
+ for (int y = -1; y < 2; y++) {
+ mural[startX + x][startY + y] = 1;
+ }
+ }
- // main tree
- makeVerticalTree(decoRNG, mural, startX, startY + 1, decoRNG.nextInt(height / 6) + height / 6, true);
+ // side branches
+ makeHorizontalTree(decoRNG, mural, startX + 1, startY, decoRNG.nextInt(width / 6) + width / 6, true);
+ makeHorizontalTree(decoRNG, mural, startX - 1, startY, decoRNG.nextInt(width / 6) + width / 6, false);
- // stripes
- makeStripes(decoRNG);
+ // main tree
+ makeVerticalTree(decoRNG, mural, startX, startY + 1, decoRNG.nextInt(height / 6) + height / 6, true);
+
+ this.mural = mural;
+
+ // stripes
+ makeStripes(decoRNG);
+ }
+ }
}
final BlockState castleMagic = TFBlocks.YELLOW_CASTLE_RUNE_BRICK.get().defaultBlockState();
diff --git a/src/main/java/twilightforest/world/components/structures/minotaurmaze/MinotaurMazeComponent.java b/src/main/java/twilightforest/world/components/structures/minotaurmaze/MinotaurMazeComponent.java
index 4e838c0145..9bd66c793b 100644
--- a/src/main/java/twilightforest/world/components/structures/minotaurmaze/MinotaurMazeComponent.java
+++ b/src/main/java/twilightforest/world/components/structures/minotaurmaze/MinotaurMazeComponent.java
@@ -36,7 +36,7 @@ public MinotaurMazeComponent(StructurePieceSerializationContext ctx, CompoundTag
// recreate maze object
maze = new TFMaze(getMazeSize(), getMazeSize(), RandomSource.create());
- setFixedMazeSeed();
+ setFixedMazeSeed(maze);
// blank out rcoords above 1 so that the room generation works properly
//TODO: re-do this. :)
@@ -62,7 +62,7 @@ public MinotaurMazeComponent(int index, int x, int y, int z, int entranceX, int
maze = new TFMaze(getMazeSize(), getMazeSize(), random);
// set the seed to a fixed value based on this maze's x and z
- setFixedMazeSeed();
+ setFixedMazeSeed(maze);
// rooms
int nrooms = 7;
@@ -95,7 +95,7 @@ private void addRoomsToMaze(int entranceX, int entranceZ, int nrooms) {
}
}
- private void setFixedMazeSeed() {
+ private void setFixedMazeSeed(TFMaze maze) {
maze.setSeed(this.boundingBox.minX() * 90342903L + this.boundingBox.minY() * 90342903L ^ this.boundingBox.minZ());
}
@@ -282,18 +282,21 @@ public void postProcess(WorldGenLevel world, StructureManager manager, ChunkGene
generateBox(world, sbb, 1, 5, 1, getDiameter() + 1, 5, getDiameter() + 1, TFBlocks.MAZESTONE.get().defaultBlockState(), stone, onlyReplaceCeiling);
generateBox(world, sbb, 1, 0, 1, getDiameter() + 1, 0, getDiameter() + 1, TFBlocks.MAZESTONE_MOSAIC.get().defaultBlockState(), stone, false);
- maze.headBlockState = TFBlocks.DECORATIVE_MAZESTONE.get().defaultBlockState();
- maze.wallBlockState = TFBlocks.MAZESTONE_BRICK.get().defaultBlockState();
- maze.rootBlockState = TFBlocks.DECORATIVE_MAZESTONE.get().defaultBlockState();
- maze.pillarBlockState = TFBlocks.CUT_MAZESTONE.get().defaultBlockState();
- maze.wallBlocks = new MazestoneProcessor();
- maze.torchRarity = 0.05F;
- maze.tall = 2;
- maze.head = 1;
- maze.roots = 1;
- maze.oddBias = 4;
-
- maze.copyToStructure(world, manager, generator, 1, 2, 1, this, sbb);
+ TFMaze maze1 = maze.clone();
+ setFixedMazeSeed(maze1);
+
+ maze1.headBlockState = TFBlocks.DECORATIVE_MAZESTONE.get().defaultBlockState();
+ maze1.wallBlockState = TFBlocks.MAZESTONE_BRICK.get().defaultBlockState();
+ maze1.rootBlockState = TFBlocks.DECORATIVE_MAZESTONE.get().defaultBlockState();
+ maze1.pillarBlockState = TFBlocks.CUT_MAZESTONE.get().defaultBlockState();
+ maze1.wallBlocks = new MazestoneProcessor();
+ maze1.torchRarity = 0.05F;
+ maze1.tall = 2;
+ maze1.head = 1;
+ maze1.roots = 1;
+ maze1.oddBias = 4;
+
+ maze1.copyToStructure(world, manager, generator, 1, 2, 1, this, sbb);
}
public int getMazeSize() {
diff --git a/src/main/java/twilightforest/world/components/structures/stronghold/StrongholdPieceWeight.java b/src/main/java/twilightforest/world/components/structures/stronghold/StrongholdPieceWeight.java
index 9c76264123..89c9bdccc7 100644
--- a/src/main/java/twilightforest/world/components/structures/stronghold/StrongholdPieceWeight.java
+++ b/src/main/java/twilightforest/world/components/structures/stronghold/StrongholdPieceWeight.java
@@ -5,7 +5,7 @@
/**
* Based off StructureStrongholdPieceWeight
*/
-public class StrongholdPieceWeight {
+public class StrongholdPieceWeight implements Cloneable {
public final Factory extends KnightStrongholdComponent> factory;
public final int pieceWeight;
@@ -36,4 +36,14 @@ public boolean canSpawnMoreStructures() {
return this.instancesLimit == 0 || this.instancesSpawned < this.instancesLimit;
}
+ @Override
+ public StrongholdPieceWeight clone() {
+ try {
+ StrongholdPieceWeight clone = (StrongholdPieceWeight) super.clone();
+ clone.instancesSpawned = 0;
+ return clone;
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError();
+ }
+ }
}
diff --git a/src/main/java/twilightforest/world/components/structures/stronghold/StrongholdPieces.java b/src/main/java/twilightforest/world/components/structures/stronghold/StrongholdPieces.java
index 6c953185d2..be2dce0d75 100644
--- a/src/main/java/twilightforest/world/components/structures/stronghold/StrongholdPieces.java
+++ b/src/main/java/twilightforest/world/components/structures/stronghold/StrongholdPieces.java
@@ -38,8 +38,9 @@ public void prepareStructurePieces() {
pieceList = new ArrayList<>();
for (StrongholdPieceWeight piece : pieceWeightArray) {
- piece.instancesSpawned = 0;
- pieceList.add(piece);
+ StrongholdPieceWeight cloned = piece.clone();
+ cloned.instancesSpawned = 0;
+ pieceList.add(cloned);
}
}
diff --git a/src/main/java/twilightforest/world/components/structures/trollcave/CloudCastleComponent.java b/src/main/java/twilightforest/world/components/structures/trollcave/CloudCastleComponent.java
index 233338ded5..044c3590e3 100644
--- a/src/main/java/twilightforest/world/components/structures/trollcave/CloudCastleComponent.java
+++ b/src/main/java/twilightforest/world/components/structures/trollcave/CloudCastleComponent.java
@@ -22,16 +22,18 @@
import twilightforest.util.BoundingBoxUtils;
import twilightforest.world.components.structures.TFStructureComponentOld;
+import java.util.concurrent.atomic.AtomicBoolean;
+
public class CloudCastleComponent extends TFStructureComponentOld {
- private boolean minerPlaced = false;
- private boolean warriorPlaced = false;
+ private final AtomicBoolean minerPlaced = new AtomicBoolean(false);
+ private final AtomicBoolean warriorPlaced = new AtomicBoolean(false);
public CloudCastleComponent(StructurePieceSerializationContext ctx, CompoundTag nbt) {
super(TFStructurePieceTypes.TFClCa.get(), nbt);
- this.minerPlaced = nbt.getBoolean("minerPlaced");
- this.warriorPlaced = nbt.getBoolean("warriorPlaced");
+ this.minerPlaced.set(nbt.getBoolean("minerPlaced"));
+ this.warriorPlaced.set(nbt.getBoolean("warriorPlaced"));
}
@SuppressWarnings("this-escape")
@@ -50,8 +52,8 @@ public CloudCastleComponent(int index, int x, int y, int z) {
@Override
protected void addAdditionalSaveData(StructurePieceSerializationContext ctx, CompoundTag tagCompound) {
super.addAdditionalSaveData(ctx, tagCompound);
- tagCompound.putBoolean("minerPlaced", this.minerPlaced);
- tagCompound.putBoolean("warriorPlaced", this.warriorPlaced);
+ tagCompound.putBoolean("minerPlaced", this.minerPlaced.get());
+ tagCompound.putBoolean("warriorPlaced", this.warriorPlaced.get());
}
@Override
@@ -92,15 +94,13 @@ public void postProcess(WorldGenLevel world, StructureManager manager, ChunkGene
this.generateAirBox(world, sbb, 8, 4, 12, 12, 11, 15);
// add giants
- if (!this.minerPlaced) {
+ if (!this.minerPlaced.get()) {
int bx = this.getWorldX(14, 14);
int by = this.getWorldY(4);
int bz = this.getWorldZ(14, 14);
BlockPos pos = new BlockPos(bx, by, bz);
- if (sbb.isInside(pos)) {
- this.minerPlaced = true;
-
+ if (sbb.isInside(pos) && this.minerPlaced.compareAndSet(false, true)) {
GiantMiner miner = TFEntities.GIANT_MINER.get().create(world.getLevel());
miner.setPos(bx, by, bz);
miner.setPersistenceRequired();
@@ -109,15 +109,13 @@ public void postProcess(WorldGenLevel world, StructureManager manager, ChunkGene
world.addFreshEntity(miner);
}
}
- if (!this.warriorPlaced) {
+ if (!this.warriorPlaced.get()) {
int bx = this.getWorldX(17, 17);
int by = this.getWorldY(4);
int bz = this.getWorldZ(17, 17);
BlockPos pos = new BlockPos(bx, by, bz);
- if (sbb.isInside(pos)) {
- this.warriorPlaced = true;
-
+ if (sbb.isInside(pos) && this.warriorPlaced.compareAndSet(false, true)) {
ArmoredGiant warrior = TFEntities.ARMORED_GIANT.get().create(world.getLevel());
warrior.setPos(bx, by, bz);
warrior.setPersistenceRequired();
diff --git a/tf-asm/src/main/java/twilightforest/asm/TFCoreMod.java b/tf-asm/src/main/java/twilightforest/asm/TFCoreMod.java
index 556afbcc8f..a4b9f225b8 100644
--- a/tf-asm/src/main/java/twilightforest/asm/TFCoreMod.java
+++ b/tf-asm/src/main/java/twilightforest/asm/TFCoreMod.java
@@ -9,6 +9,7 @@
import twilightforest.asm.transformers.beardifier.InitializeCustomBeardifierFieldsDuringCreateNoiseChunkTransformer;
import twilightforest.asm.transformers.book.ModifyWrittenBookNameTransformer;
import twilightforest.asm.transformers.chunk.ChunkStatusTaskTransformer;
+import twilightforest.asm.transformers.chunk.NoiseBasedChunkGeneratorTransformer;
import twilightforest.asm.transformers.cloud.IsRainingAtTransformer;
import twilightforest.asm.transformers.conquered.StructureStartLoadStaticTransformer;
import twilightforest.asm.transformers.foliage.FoliageColorResolverTransformer;
@@ -39,6 +40,7 @@ public Iterable extends ITransformer>> getTransformers() {
// chunk
new ChunkStatusTaskTransformer(),
+ new NoiseBasedChunkGeneratorTransformer(),
// cloud
new IsRainingAtTransformer(),
diff --git a/tf-asm/src/main/java/twilightforest/asm/transformers/chunk/NoiseBasedChunkGeneratorTransformer.java b/tf-asm/src/main/java/twilightforest/asm/transformers/chunk/NoiseBasedChunkGeneratorTransformer.java
new file mode 100644
index 0000000000..667ac72809
--- /dev/null
+++ b/tf-asm/src/main/java/twilightforest/asm/transformers/chunk/NoiseBasedChunkGeneratorTransformer.java
@@ -0,0 +1,59 @@
+package twilightforest.asm.transformers.chunk;
+
+import cpw.mods.modlauncher.api.ITransformer;
+import cpw.mods.modlauncher.api.ITransformerVotingContext;
+import cpw.mods.modlauncher.api.TargetType;
+import cpw.mods.modlauncher.api.TransformerVoteResult;
+import net.neoforged.coremod.api.ASMAPI;
+import org.jetbrains.annotations.NotNull;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.tree.MethodInsnNode;
+import org.objectweb.asm.tree.MethodNode;
+import twilightforest.asm.ASMUtil;
+
+import java.util.Set;
+
+/**
+ * {@link twilightforest.ASMHooks#tryRecreateBiomeResolver}
+ */
+public class NoiseBasedChunkGeneratorTransformer implements ITransformer {
+
+ @Override
+ public @NotNull MethodNode transform(MethodNode node, ITransformerVotingContext context) {
+ ASMUtil.findVarInstructions(node, Opcodes.ASTORE, 6) // BiomeResolver biomeresolver
+ .findFirst()
+ .ifPresent(varInsnNode -> node.instructions.insertBefore(
+ varInsnNode,
+ ASMAPI.listOf(
+ new MethodInsnNode(
+ Opcodes.INVOKESTATIC,
+ "twilightforest/ASMHooks",
+ "tryRecreateBiomeResolver",
+ "(Lnet/minecraft/world/level/biome/BiomeResolver;)Lnet/minecraft/world/level/biome/BiomeResolver;",
+ false
+ )
+ )
+ ));
+ return node;
+ }
+
+ @Override
+ public @NotNull TransformerVoteResult castVote(ITransformerVotingContext context) {
+ return TransformerVoteResult.YES;
+ }
+
+ @Override
+ public @NotNull Set> targets() {
+ return Set.of(Target.targetMethod(
+ "net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator",
+ "doCreateBiomes",
+ "(Lnet/minecraft/world/level/levelgen/blending/Blender;Lnet/minecraft/world/level/levelgen/RandomState;Lnet/minecraft/world/level/StructureManager;Lnet/minecraft/world/level/chunk/ChunkAccess;)V"
+ ));
+ }
+
+ @Override
+ public @NotNull TargetType getTargetType() {
+ return TargetType.METHOD;
+ }
+
+}