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 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> 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; + } + +}