package net.minecraft.command.commands; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import net.minecraft.block.Block; import net.minecraft.block.material.Material; import net.minecraft.block.state.IBlockState; import net.minecraft.command.CommandException; import net.minecraft.command.CommandResultStats; import net.minecraft.command.CommandUtilities; import net.minecraft.command.ICommandSender; import net.minecraft.command.SyntaxErrorException; import net.minecraft.command.arg.CommandArg; import net.minecraft.command.collections.TypeIDs; import net.minecraft.command.construction.CommandConstructable; import net.minecraft.command.construction.CommandDescriptorDefault.CParserData; import net.minecraft.init.Blocks; import net.minecraft.nbt.NBTTagCompound; import net.minecraft.util.BlockPos; import net.minecraft.world.World; import net.minecraft.world.gen.structure.StructureBoundingBox; public class CommandFill extends CommandArg<Integer> { public static final CommandConstructable constructable = new CommandConstructable() { @Override public CommandArg<Integer> construct(final CParserData data) throws SyntaxErrorException { return CommandFill.construct(data.getPath(), data, false); } }; public static final CommandConstructable fastConstructable = new CommandConstructable() { @Override public CommandArg<Integer> construct(final CParserData data) throws SyntaxErrorException { return CommandFill.construct(data.getPath(1), data, true); } }; private static final CommandArg<Integer> construct(final String mode, final CParserData data, final boolean fast) { if (mode == null) return new CommandFill(data, fast); switch (mode) { case "replace": if (data.params.get(4) == null) return new CommandFill( data.get(TypeIDs.BlockPos), data.get(TypeIDs.BlockPos), data.get(TypeIDs.BlockID), data.get(TypeIDs.Integer), data.get(TypeIDs.NBTCompound, 6), fast); return new Replace( data.get(TypeIDs.BlockPos), data.get(TypeIDs.BlockPos), data.get(TypeIDs.BlockID), data.get(TypeIDs.Integer), data.get(TypeIDs.BlockID), data.get(TypeIDs.Integer), data.get(TypeIDs.NBTCompound), fast); case "destroy": return new Destroy(data, fast); case "keep": return new Keep(data, fast); case "outline": return new Outline(data, fast); case "hollow": return new Hollow(data, fast); } return null; } private final CommandArg<BlockPos> pos1; private final CommandArg<BlockPos> pos2; private final CommandArg<Block> blockID; private final CommandArg<Integer> meta; private final CommandArg<NBTTagCompound> nbt; private final boolean fast; public CommandFill(final CommandArg<BlockPos> pos1, final CommandArg<BlockPos> pos2, final CommandArg<Block> blockID, final CommandArg<Integer> meta, final CommandArg<NBTTagCompound> nbt, final boolean fast) { this.pos1 = pos1; this.pos2 = pos2; this.blockID = blockID; this.meta = meta; this.nbt = nbt; this.fast = fast; } private CommandFill(final CParserData data, final boolean fast) { this.pos1 = data.get(TypeIDs.BlockPos); this.pos2 = data.get(TypeIDs.BlockPos); this.blockID = data.get(TypeIDs.BlockID); this.meta = data.get(TypeIDs.Integer); this.nbt = data.get(TypeIDs.NBTCompound); this.fast = fast; } @Override public Integer eval(final ICommandSender sender) throws CommandException { final BlockPos pos1 = this.pos1.eval(sender); final BlockPos pos2 = this.pos2.eval(sender); final Block blockID = this.blockID.eval(sender); final int meta = this.meta == null ? 0 : this.meta.eval(sender); this.evalArgs(sender); final NBTTagCompound nbt = this.nbt == null ? null : new NBTTagCompound.CopyOnWrite(this.nbt.eval(sender)); sender.func_174794_a(CommandResultStats.Type.AFFECTED_BLOCKS, 0); CommandUtilities.checkInt(meta, 0, 15); final IBlockState state = blockID.getStateFromMeta(meta); final StructureBoundingBox box = new StructureBoundingBox(pos1, pos2); final int size = box.getXSize() * box.getYSize() * box.getZSize(); if (size > 32768) throw new CommandException("commands.fill.tooManyBlocks", size, 32768); if (box.minY < 0 || box.maxY >= 256) throw new CommandException("commands.fill.outOfWorld"); final World world = sender.getEntityWorld(); if (!world.isAreaLoaded(box)) throw new CommandException("commands.fill.outOfWorld"); this.checkArgs(); final int flags = nbt == null ? 26 : 18; int succ = 0; if (this.fast) for (int z = box.minZ; z <= box.maxZ; ++z) for (int y = box.minY; y <= box.maxY; ++y) for (int x = box.minX; x <= box.maxX; ++x) { final BlockPos pos = new BlockPos(x, y, z); final IBlockState newState = this.clear(world, box, pos, state); if (newState == null) continue; final boolean hasTe = newState.getBlock().hasTileEntity(); if (world.setBlockState(pos, newState, flags) || hasTe) ++succ; if (hasTe && nbt != null) CommandUtilities.setNBT(world, pos, nbt); } else { final List<BlockPos> changedPositions = new ArrayList<>(size); final List<IBlockState> targetStates = new ArrayList<>(size); for (int z = box.minZ; z <= box.maxZ; ++z) for (int y = box.minY; y <= box.maxY; ++y) for (int x = box.minX; x <= box.maxX; ++x) { final BlockPos pos = new BlockPos(x, y, z); final IBlockState newState = this.clear(world, box, pos, state); if (newState != null) { changedPositions.add(pos); targetStates.add(newState); ++succ; } } final Iterator<IBlockState> it = targetStates.iterator(); for (final BlockPos pos : changedPositions) { final IBlockState targetState = it.next(); world.setBlockState(pos, targetState, flags); if (targetState.getBlock().hasTileEntity() && nbt != null) CommandUtilities.setNBT(world, pos, nbt); world.func_175722_b(pos, blockID); } } if (succ == 0) throw new CommandException("commands.fill.failed"); sender.func_174794_a(CommandResultStats.Type.AFFECTED_BLOCKS, succ); CommandUtilities.notifyOperators(sender, "commands.fill.success", succ); return succ; } protected void evalArgs(@SuppressWarnings("unused") final ICommandSender sender) throws CommandException { } protected void checkArgs() throws CommandException { } protected IBlockState clear(final World world, @SuppressWarnings("unused") final StructureBoundingBox box, final BlockPos pos, final IBlockState targetState) { if (this.fast) return targetState; return iClear(world, pos, targetState, world.getBlockState(pos)); } protected final IBlockState clear(final World world, final BlockPos pos, final IBlockState targetState, final IBlockState oldState) { if (this.fast) return targetState; return iClear(world, pos, targetState, oldState); } private static IBlockState iClear(final World world, final BlockPos pos, final IBlockState targetState, final IBlockState oldState) { if (oldState == targetState) return targetState.getBlock().hasTileEntity() ? targetState : null; world.setBlockState(pos, CommandUtilities.getTempState(oldState, targetState), 18); return targetState; } private static final class Destroy extends CommandFill { public Destroy(final CParserData data, final boolean fast) { super(data, fast); } @Override protected IBlockState clear(final World world, final StructureBoundingBox box, final BlockPos pos, final IBlockState targetState) { world.destroyBlock(pos, true); return targetState; } } private static final class Keep extends CommandFill { public Keep(final CParserData data, final boolean fast) { super(data, fast); } @Override protected IBlockState clear(final World world, final StructureBoundingBox box, final BlockPos pos, final IBlockState targetState) { final IBlockState oldState = world.getBlockState(pos); if (oldState.getBlock().getMaterial() == Material.air) return super.clear(world, pos, targetState, oldState); return null; } } private static final class Replace extends CommandFill { private final CommandArg<Block> filterBlock; private final CommandArg<Integer> filterMeta; public Replace(final CommandArg<BlockPos> pos1, final CommandArg<BlockPos> pos2, final CommandArg<Block> blockID, final CommandArg<Integer> meta, final CommandArg<Block> blockFilter, final CommandArg<Integer> metaFilter, final CommandArg<NBTTagCompound> nbt, final boolean fast) { super(pos1, pos2, blockID, meta, nbt, fast); this.filterBlock = blockFilter; this.filterMeta = metaFilter; } private Block eFilterBlock; private int eFilterMeta; @Override protected void evalArgs(final ICommandSender sender) throws CommandException { this.eFilterBlock = this.filterBlock.eval(sender); if (this.filterMeta != null) this.eFilterMeta = this.filterMeta.eval(sender); } @Override protected void checkArgs() throws CommandException { if (this.filterMeta != null) CommandUtilities.checkInt(this.eFilterMeta, 0, 15); } @Override protected IBlockState clear(final World world, final StructureBoundingBox box, final BlockPos pos, final IBlockState targetState) { final IBlockState oldState = world.getBlockState(pos); if (oldState.getBlock() == this.eFilterBlock && (this.filterMeta == null || this.eFilterMeta == oldState.getBlock().getMetaFromState(oldState))) return super.clear(world, pos, targetState, oldState); return null; } } private static final class Outline extends CommandFill { public Outline(final CParserData data, final boolean fast) { super(data, fast); } @Override protected IBlockState clear(final World world, final StructureBoundingBox box, final BlockPos pos, final IBlockState targetState) { if (pos.getX() != box.minX && pos.getX() != box.maxX && pos.getY() != box.minY && pos.getY() != box.maxY && pos.getZ() != box.minZ && pos.getZ() != box.maxZ) return null; return super.clear(world, box, pos, targetState); } } private static final class Hollow extends CommandFill { public Hollow(final CParserData data, final boolean fast) { super(data, fast); } @Override protected IBlockState clear(final World world, final StructureBoundingBox box, final BlockPos pos, final IBlockState targetState) { return super.clear(world, box, pos, pos.getX() != box.minX && pos.getX() != box.maxX && pos.getY() != box.minY && pos.getY() != box.maxY && pos.getZ() != box.minZ && pos.getZ() != box.maxZ ? Blocks.air.getDefaultState() : targetState); } } }