Code/net/minecraft/server/commands/SpreadPlayersCommand.java

376 lines
17 KiB
Java

package net.minecraft.server.commands;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.arguments.BoolArgumentType;
import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.arguments.IntegerArgumentType;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.Dynamic2CommandExceptionType;
import com.mojang.brigadier.exceptions.Dynamic4CommandExceptionType;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.commands.arguments.EntityArgument;
import net.minecraft.commands.arguments.coordinates.Vec2Argument;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.network.chat.Component;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.scores.Team;
public class SpreadPlayersCommand {
private static final int MAX_ITERATION_COUNT = 10000;
private static final Dynamic4CommandExceptionType ERROR_FAILED_TO_SPREAD_TEAMS = new Dynamic4CommandExceptionType(
(p_308883_, p_308884_, p_308885_, p_308886_) -> Component.translatableEscape("commands.spreadplayers.failed.teams", p_308883_, p_308884_, p_308885_, p_308886_)
);
private static final Dynamic4CommandExceptionType ERROR_FAILED_TO_SPREAD_ENTITIES = new Dynamic4CommandExceptionType(
(p_308887_, p_308888_, p_308889_, p_308890_) -> Component.translatableEscape(
"commands.spreadplayers.failed.entities", p_308887_, p_308888_, p_308889_, p_308890_
)
);
private static final Dynamic2CommandExceptionType ERROR_INVALID_MAX_HEIGHT = new Dynamic2CommandExceptionType(
(p_308892_, p_308893_) -> Component.translatableEscape("commands.spreadplayers.failed.invalid.height", p_308892_, p_308893_)
);
public static void register(CommandDispatcher<CommandSourceStack> p_138697_) {
p_138697_.register(
Commands.literal("spreadplayers")
.requires(p_201852_ -> p_201852_.hasPermission(2))
.then(
Commands.argument("center", Vec2Argument.vec2())
.then(
Commands.argument("spreadDistance", FloatArgumentType.floatArg(0.0F))
.then(
Commands.argument("maxRange", FloatArgumentType.floatArg(1.0F))
.then(
Commands.argument("respectTeams", BoolArgumentType.bool())
.then(
Commands.argument("targets", EntityArgument.entities())
.executes(
p_390103_ -> spreadPlayers(
p_390103_.getSource(),
Vec2Argument.getVec2(p_390103_, "center"),
FloatArgumentType.getFloat(p_390103_, "spreadDistance"),
FloatArgumentType.getFloat(p_390103_, "maxRange"),
p_390103_.getSource().getLevel().getMaxY() + 1,
BoolArgumentType.getBool(p_390103_, "respectTeams"),
EntityArgument.getEntities(p_390103_, "targets")
)
)
)
)
.then(
Commands.literal("under")
.then(
Commands.argument("maxHeight", IntegerArgumentType.integer())
.then(
Commands.argument("respectTeams", BoolArgumentType.bool())
.then(
Commands.argument("targets", EntityArgument.entities())
.executes(
p_201850_ -> spreadPlayers(
p_201850_.getSource(),
Vec2Argument.getVec2(p_201850_, "center"),
FloatArgumentType.getFloat(p_201850_, "spreadDistance"),
FloatArgumentType.getFloat(p_201850_, "maxRange"),
IntegerArgumentType.getInteger(p_201850_, "maxHeight"),
BoolArgumentType.getBool(p_201850_, "respectTeams"),
EntityArgument.getEntities(p_201850_, "targets")
)
)
)
)
)
)
)
)
)
);
}
private static int spreadPlayers(
CommandSourceStack p_138703_,
Vec2 p_138704_,
float p_138705_,
float p_138706_,
int p_138707_,
boolean p_138708_,
Collection<? extends Entity> p_138709_
) throws CommandSyntaxException {
ServerLevel serverlevel = p_138703_.getLevel();
int i = serverlevel.getMinY();
if (p_138707_ < i) {
throw ERROR_INVALID_MAX_HEIGHT.create(p_138707_, i);
} else {
RandomSource randomsource = RandomSource.create();
double d0 = p_138704_.x - p_138706_;
double d1 = p_138704_.y - p_138706_;
double d2 = p_138704_.x + p_138706_;
double d3 = p_138704_.y + p_138706_;
SpreadPlayersCommand.Position[] aspreadplayerscommand$position = createInitialPositions(
randomsource, p_138708_ ? getNumberOfTeams(p_138709_) : p_138709_.size(), d0, d1, d2, d3
);
spreadPositions(p_138704_, p_138705_, serverlevel, randomsource, d0, d1, d2, d3, p_138707_, aspreadplayerscommand$position, p_138708_);
double d4 = setPlayerPositions(p_138709_, serverlevel, aspreadplayerscommand$position, p_138707_, p_138708_);
p_138703_.sendSuccess(
() -> Component.translatable(
"commands.spreadplayers.success." + (p_138708_ ? "teams" : "entities"),
aspreadplayerscommand$position.length,
p_138704_.x,
p_138704_.y,
String.format(Locale.ROOT, "%.2f", d4)
),
true
);
return aspreadplayerscommand$position.length;
}
}
private static int getNumberOfTeams(Collection<? extends Entity> p_138728_) {
Set<Team> set = Sets.newHashSet();
for (Entity entity : p_138728_) {
if (entity instanceof Player) {
set.add(entity.getTeam());
} else {
set.add(null);
}
}
return set.size();
}
private static void spreadPositions(
Vec2 p_214741_,
double p_214742_,
ServerLevel p_214743_,
RandomSource p_214744_,
double p_214745_,
double p_214746_,
double p_214747_,
double p_214748_,
int p_214749_,
SpreadPlayersCommand.Position[] p_214750_,
boolean p_214751_
) throws CommandSyntaxException {
boolean flag = true;
double d0 = Float.MAX_VALUE;
int i;
for (i = 0; i < 10000 && flag; i++) {
flag = false;
d0 = Float.MAX_VALUE;
for (int j = 0; j < p_214750_.length; j++) {
SpreadPlayersCommand.Position spreadplayerscommand$position = p_214750_[j];
int k = 0;
SpreadPlayersCommand.Position spreadplayerscommand$position1 = new SpreadPlayersCommand.Position();
for (int l = 0; l < p_214750_.length; l++) {
if (j != l) {
SpreadPlayersCommand.Position spreadplayerscommand$position2 = p_214750_[l];
double d1 = spreadplayerscommand$position.dist(spreadplayerscommand$position2);
d0 = Math.min(d1, d0);
if (d1 < p_214742_) {
k++;
spreadplayerscommand$position1.x = spreadplayerscommand$position1.x
+ (spreadplayerscommand$position2.x - spreadplayerscommand$position.x);
spreadplayerscommand$position1.z = spreadplayerscommand$position1.z
+ (spreadplayerscommand$position2.z - spreadplayerscommand$position.z);
}
}
}
if (k > 0) {
spreadplayerscommand$position1.x /= k;
spreadplayerscommand$position1.z /= k;
double d2 = spreadplayerscommand$position1.getLength();
if (d2 > 0.0) {
spreadplayerscommand$position1.normalize();
spreadplayerscommand$position.moveAway(spreadplayerscommand$position1);
} else {
spreadplayerscommand$position.randomize(p_214744_, p_214745_, p_214746_, p_214747_, p_214748_);
}
flag = true;
}
if (spreadplayerscommand$position.clamp(p_214745_, p_214746_, p_214747_, p_214748_)) {
flag = true;
}
}
if (!flag) {
for (SpreadPlayersCommand.Position spreadplayerscommand$position3 : p_214750_) {
if (!spreadplayerscommand$position3.isSafe(p_214743_, p_214749_)) {
spreadplayerscommand$position3.randomize(p_214744_, p_214745_, p_214746_, p_214747_, p_214748_);
flag = true;
}
}
}
}
if (d0 == Float.MAX_VALUE) {
d0 = 0.0;
}
if (i >= 10000) {
if (p_214751_) {
throw ERROR_FAILED_TO_SPREAD_TEAMS.create(p_214750_.length, p_214741_.x, p_214741_.y, String.format(Locale.ROOT, "%.2f", d0));
} else {
throw ERROR_FAILED_TO_SPREAD_ENTITIES.create(p_214750_.length, p_214741_.x, p_214741_.y, String.format(Locale.ROOT, "%.2f", d0));
}
}
}
private static double setPlayerPositions(
Collection<? extends Entity> p_138730_, ServerLevel p_138731_, SpreadPlayersCommand.Position[] p_138732_, int p_138733_, boolean p_138734_
) {
double d0 = 0.0;
int i = 0;
Map<Team, SpreadPlayersCommand.Position> map = Maps.newHashMap();
for (Entity entity : p_138730_) {
SpreadPlayersCommand.Position spreadplayerscommand$position;
if (p_138734_) {
Team team = entity instanceof Player ? entity.getTeam() : null;
if (!map.containsKey(team)) {
map.put(team, p_138732_[i++]);
}
spreadplayerscommand$position = map.get(team);
} else {
spreadplayerscommand$position = p_138732_[i++];
}
entity.teleportTo(
p_138731_,
Mth.floor(spreadplayerscommand$position.x) + 0.5,
spreadplayerscommand$position.getSpawnY(p_138731_, p_138733_),
Mth.floor(spreadplayerscommand$position.z) + 0.5,
Set.of(),
entity.getYRot(),
entity.getXRot(),
true
);
double d2 = Double.MAX_VALUE;
for (SpreadPlayersCommand.Position spreadplayerscommand$position1 : p_138732_) {
if (spreadplayerscommand$position != spreadplayerscommand$position1) {
double d1 = spreadplayerscommand$position.dist(spreadplayerscommand$position1);
d2 = Math.min(d1, d2);
}
}
d0 += d2;
}
return p_138730_.size() < 2 ? 0.0 : d0 / p_138730_.size();
}
private static SpreadPlayersCommand.Position[] createInitialPositions(
RandomSource p_214734_, int p_214735_, double p_214736_, double p_214737_, double p_214738_, double p_214739_
) {
SpreadPlayersCommand.Position[] aspreadplayerscommand$position = new SpreadPlayersCommand.Position[p_214735_];
for (int i = 0; i < aspreadplayerscommand$position.length; i++) {
SpreadPlayersCommand.Position spreadplayerscommand$position = new SpreadPlayersCommand.Position();
spreadplayerscommand$position.randomize(p_214734_, p_214736_, p_214737_, p_214738_, p_214739_);
aspreadplayerscommand$position[i] = spreadplayerscommand$position;
}
return aspreadplayerscommand$position;
}
static class Position {
double x;
double z;
double dist(SpreadPlayersCommand.Position p_138768_) {
double d0 = this.x - p_138768_.x;
double d1 = this.z - p_138768_.z;
return Math.sqrt(d0 * d0 + d1 * d1);
}
void normalize() {
double d0 = this.getLength();
this.x /= d0;
this.z /= d0;
}
double getLength() {
return Math.sqrt(this.x * this.x + this.z * this.z);
}
public void moveAway(SpreadPlayersCommand.Position p_138777_) {
this.x = this.x - p_138777_.x;
this.z = this.z - p_138777_.z;
}
public boolean clamp(double p_138754_, double p_138755_, double p_138756_, double p_138757_) {
boolean flag = false;
if (this.x < p_138754_) {
this.x = p_138754_;
flag = true;
} else if (this.x > p_138756_) {
this.x = p_138756_;
flag = true;
}
if (this.z < p_138755_) {
this.z = p_138755_;
flag = true;
} else if (this.z > p_138757_) {
this.z = p_138757_;
flag = true;
}
return flag;
}
public int getSpawnY(BlockGetter p_138759_, int p_138760_) {
BlockPos.MutableBlockPos blockpos$mutableblockpos = new BlockPos.MutableBlockPos(this.x, (double)(p_138760_ + 1), this.z);
boolean flag = p_138759_.getBlockState(blockpos$mutableblockpos).isAir();
blockpos$mutableblockpos.move(Direction.DOWN);
boolean flag1 = p_138759_.getBlockState(blockpos$mutableblockpos).isAir();
while (blockpos$mutableblockpos.getY() > p_138759_.getMinY()) {
blockpos$mutableblockpos.move(Direction.DOWN);
boolean flag2 = p_138759_.getBlockState(blockpos$mutableblockpos).isAir();
if (!flag2 && flag1 && flag) {
return blockpos$mutableblockpos.getY() + 1;
}
flag = flag1;
flag1 = flag2;
}
return p_138760_ + 1;
}
public boolean isSafe(BlockGetter p_138774_, int p_138775_) {
BlockPos blockpos = BlockPos.containing(this.x, this.getSpawnY(p_138774_, p_138775_) - 1, this.z);
BlockState blockstate = p_138774_.getBlockState(blockpos);
return blockpos.getY() < p_138775_ && !blockstate.liquid() && !blockstate.is(BlockTags.FIRE);
}
public void randomize(RandomSource p_214753_, double p_214754_, double p_214755_, double p_214756_, double p_214757_) {
this.x = Mth.nextDouble(p_214753_, p_214754_, p_214756_);
this.z = Mth.nextDouble(p_214753_, p_214755_, p_214757_);
}
}
}