package net.minecraft.server.commands; import com.mojang.brigadier.CommandDispatcher; import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.exceptions.CommandSyntaxException; import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType; import com.mojang.brigadier.exceptions.SimpleCommandExceptionType; import com.mojang.datafixers.util.Either; import java.util.ArrayList; import java.util.List; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Predicate; import java.util.function.Supplier; import net.minecraft.commands.CommandBuildContext; import net.minecraft.commands.CommandSourceStack; import net.minecraft.commands.Commands; import net.minecraft.commands.arguments.ResourceArgument; import net.minecraft.commands.arguments.ResourceOrTagArgument; import net.minecraft.commands.arguments.coordinates.BlockPosArgument; import net.minecraft.core.BlockPos; import net.minecraft.core.Holder; import net.minecraft.core.QuartPos; import net.minecraft.core.SectionPos; import net.minecraft.core.registries.Registries; import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.GameRules; import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.BiomeResolver; import net.minecraft.world.level.biome.Climate; import net.minecraft.world.level.chunk.ChunkAccess; import net.minecraft.world.level.chunk.status.ChunkStatus; import net.minecraft.world.level.levelgen.structure.BoundingBox; import org.apache.commons.lang3.mutable.MutableInt; public class FillBiomeCommand { public static final SimpleCommandExceptionType ERROR_NOT_LOADED = new SimpleCommandExceptionType(Component.translatable("argument.pos.unloaded")); private static final Dynamic2CommandExceptionType ERROR_VOLUME_TOO_LARGE = new Dynamic2CommandExceptionType( (p_308696_, p_308697_) -> Component.translatableEscape("commands.fillbiome.toobig", p_308696_, p_308697_) ); public static void register(CommandDispatcher p_261867_, CommandBuildContext p_262155_) { p_261867_.register( Commands.literal("fillbiome") .requires(p_261890_ -> p_261890_.hasPermission(2)) .then( Commands.argument("from", BlockPosArgument.blockPos()) .then( Commands.argument("to", BlockPosArgument.blockPos()) .then( Commands.argument("biome", ResourceArgument.resource(p_262155_, Registries.BIOME)) .executes( p_262554_ -> fill( p_262554_.getSource(), BlockPosArgument.getLoadedBlockPos(p_262554_, "from"), BlockPosArgument.getLoadedBlockPos(p_262554_, "to"), ResourceArgument.getResource(p_262554_, "biome", Registries.BIOME), p_308700_ -> true ) ) .then( Commands.literal("replace") .then( Commands.argument("filter", ResourceOrTagArgument.resourceOrTag(p_262155_, Registries.BIOME)) .executes( p_262544_ -> fill( p_262544_.getSource(), BlockPosArgument.getLoadedBlockPos(p_262544_, "from"), BlockPosArgument.getLoadedBlockPos(p_262544_, "to"), ResourceArgument.getResource(p_262544_, "biome", Registries.BIOME), ResourceOrTagArgument.getResourceOrTag(p_262544_, "filter", Registries.BIOME)::test ) ) ) ) ) ) ) ); } private static int quantize(int p_261998_) { return QuartPos.toBlock(QuartPos.fromBlock(p_261998_)); } private static BlockPos quantize(BlockPos p_262148_) { return new BlockPos(quantize(p_262148_.getX()), quantize(p_262148_.getY()), quantize(p_262148_.getZ())); } private static BiomeResolver makeResolver( MutableInt p_262615_, ChunkAccess p_262698_, BoundingBox p_262622_, Holder p_262705_, Predicate> p_262695_ ) { return (p_262550_, p_262551_, p_262552_, p_262553_) -> { int i = QuartPos.toBlock(p_262550_); int j = QuartPos.toBlock(p_262551_); int k = QuartPos.toBlock(p_262552_); Holder holder = p_262698_.getNoiseBiome(p_262550_, p_262551_, p_262552_); if (p_262622_.isInside(i, j, k) && p_262695_.test(holder)) { p_262615_.increment(); return p_262705_; } else { return holder; } }; } public static Either fill(ServerLevel p_312613_, BlockPos p_311970_, BlockPos p_311934_, Holder p_310918_) { return fill(p_312613_, p_311970_, p_311934_, p_310918_, p_262543_ -> true, p_308701_ -> { }); } public static Either fill( ServerLevel p_312916_, BlockPos p_312866_, BlockPos p_311741_, Holder p_311864_, Predicate> p_311950_, Consumer> p_313249_ ) { BlockPos blockpos = quantize(p_312866_); BlockPos blockpos1 = quantize(p_311741_); BoundingBox boundingbox = BoundingBox.fromCorners(blockpos, blockpos1); int i = boundingbox.getXSpan() * boundingbox.getYSpan() * boundingbox.getZSpan(); int j = p_312916_.getGameRules().getInt(GameRules.RULE_COMMAND_MODIFICATION_BLOCK_LIMIT); if (i > j) { return Either.right(ERROR_VOLUME_TOO_LARGE.create(j, i)); } else { List list = new ArrayList<>(); for (int k = SectionPos.blockToSectionCoord(boundingbox.minZ()); k <= SectionPos.blockToSectionCoord(boundingbox.maxZ()); k++) { for (int l = SectionPos.blockToSectionCoord(boundingbox.minX()); l <= SectionPos.blockToSectionCoord(boundingbox.maxX()); l++) { ChunkAccess chunkaccess = p_312916_.getChunk(l, k, ChunkStatus.FULL, false); if (chunkaccess == null) { return Either.right(ERROR_NOT_LOADED.create()); } list.add(chunkaccess); } } MutableInt mutableint = new MutableInt(0); for (ChunkAccess chunkaccess1 : list) { chunkaccess1.fillBiomesFromNoise(makeResolver(mutableint, chunkaccess1, boundingbox, p_311864_, p_311950_), p_312916_.getChunkSource().randomState().sampler()); chunkaccess1.markUnsaved(); } p_312916_.getChunkSource().chunkMap.resendBiomesForChunks(list); p_313249_.accept( () -> Component.translatable( "commands.fillbiome.success.count", mutableint.getValue(), boundingbox.minX(), boundingbox.minY(), boundingbox.minZ(), boundingbox.maxX(), boundingbox.maxY(), boundingbox.maxZ() ) ); return Either.left(mutableint.getValue()); } } private static int fill( CommandSourceStack p_262664_, BlockPos p_262651_, BlockPos p_262678_, Holder.Reference p_262612_, Predicate> p_262697_ ) throws CommandSyntaxException { Either either = fill( p_262664_.getLevel(), p_262651_, p_262678_, p_262612_, p_262697_, p_308699_ -> p_262664_.sendSuccess(p_308699_, true) ); Optional optional = either.right(); if (optional.isPresent()) { throw (CommandSyntaxException)optional.get(); } else { return either.left().get(); } } }