the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at master 328 lines 11 kB view raw
1/* 2package net.minecraft.commands.common; 3 4import java.util.*; 5 6import net.minecraft.commands.*; 7import net.minecraft.commands.exceptions.*; 8import net.minecraft.network.chat.ChatMessageComponent; 9import net.minecraft.server.MinecraftServer; 10import net.minecraft.server.level.ServerPlayer; 11import net.minecraft.util.Mth; 12import net.minecraft.world.entity.LivingEntity; 13import net.minecraft.world.entity.player.Player; 14import net.minecraft.world.level.Level; 15import net.minecraft.world.level.material.Material; 16import net.minecraft.world.level.tile.Tile; 17import net.minecraft.world.scores.Team; 18 19import com.google.common.collect.*; 20 21public class SpreadPlayersCommand extends BaseCommand { 22 private static final int MAX_ITERATION_COUNT = 10000; 23 24 @Override 25 public String getName() { 26 return "spreadplayers"; 27 } 28 29 @Override 30 public int getPermissionLevel() { 31 return LEVEL_GAMEMASTERS; 32 } 33 34 @Override 35 public String getUsage(CommandSender source) { 36 return "commands.spreadplayers.usage"; 37 } 38 39 @Override 40 public void execute(CommandSender source, String[] args) { 41 if (args.length < 6) throw new UsageException("commands.spreadplayers.usage"); 42 int index = 0; 43 double x = convertArgToCoordinate(source, Double.NaN, args[index++]); 44 double z = convertArgToCoordinate(source, Double.NaN, args[index++]); 45 double minDist = convertArgToDouble(source, args[index++], 0); 46 double maxDist = convertArgToDouble(source, args[index++], minDist + 1); 47 boolean respectTeams = convertArgToBoolean(source, args[index++]); 48 49 List<LivingEntity> players = Lists.newArrayList(); 50 51 while (index < args.length) { 52 String arg = args[index++]; 53 54 if (PlayerSelector.isPattern(arg)) { 55 ServerPlayer[] result = PlayerSelector.getPlayers(source, arg); 56 57 if (result != null && result.length != 0) { 58 Collections.addAll(players, result); 59 } else { 60 throw new PlayerNotFoundException(); 61 } 62 } else { 63 Player player = MinecraftServer.getInstance().getPlayers().getPlayer(arg); 64 65 if (player != null) { 66 players.add(player); 67 } else { 68 throw new PlayerNotFoundException(); 69 } 70 } 71 } 72 73 if (players.isEmpty()) { 74 throw new PlayerNotFoundException(); 75 } 76 77 source.sendMessage(ChatMessageComponent.forTranslation("commands.spreadplayers.spreading." + (respectTeams ? "teams" : "players"), joinPlayerNames(players), x, z, minDist, maxDist)); 78 79 spreadPlayers(source, players, new Position(x, z), minDist, maxDist, players.get(0).level, respectTeams); 80 } 81 82 private void spreadPlayers(CommandSender source, List<LivingEntity> players, Position center, double spreadDist, double maxDistFromCenter, Level level, boolean respectTeams) { 83 Random random = new Random(); 84 double minX = center.x - maxDistFromCenter; 85 double minZ = center.z - maxDistFromCenter; 86 double maxX = center.x + maxDistFromCenter; 87 double maxZ = center.z + maxDistFromCenter; 88 89 Position[] positions = createInitialPositions(random, respectTeams ? getNumberOfTeams(players) : players.size(), minX, minZ, maxX, maxZ); 90 int iterations = spreadPositions(center, spreadDist, level, random, minX, minZ, maxX, maxZ, positions, respectTeams); 91 double avgDistance = setPlayerPositions(players, level, positions, respectTeams); 92 93 logAdminAction(source, "commands.spreadplayers.success." + (respectTeams ? "teams" : "players"), positions.length, center.x, center.z); 94 if (positions.length > 1) source.sendMessage(ChatMessageComponent.forTranslation("commands.spreadplayers.info." + (respectTeams ? "teams" : "players"), String.format("%.2f", avgDistance), 95 iterations)); 96 } 97 98 private int getNumberOfTeams(List<LivingEntity> players) { 99 Set<Team> teams = Sets.newHashSet(); 100 101 for (LivingEntity player : players) { 102 if (player instanceof Player) { 103 teams.add(((Player) player).getTeam()); 104 } else { 105 teams.add(null); 106 } 107 } 108 109 return teams.size(); 110 } 111 112 private int spreadPositions(Position center, double spreadDist, Level level, Random random, double minX, double minZ, double maxX, double maxZ, Position[] positions, boolean respectTeams) { 113 boolean hasCollisions = true; 114 int iteration; 115 double minDistance = Float.MAX_VALUE; 116 117 for (iteration = 0; iteration < MAX_ITERATION_COUNT && hasCollisions; iteration++) { 118 hasCollisions = false; 119 minDistance = Float.MAX_VALUE; 120 121 for (int i = 0; i < positions.length; i++) { 122 Position position = positions[i]; 123 int neighbourCount = 0; 124 Position averageNeighbourPos = new Position(); 125 126 for (int j = 0; j < positions.length; j++) { 127 if (i == j) continue; 128 Position neighbour = positions[j]; 129 130 double dist = position.dist(neighbour); 131 minDistance = Math.min(dist, minDistance); 132 if (dist < spreadDist) { 133 neighbourCount++; 134 averageNeighbourPos.x += neighbour.x - position.x; 135 averageNeighbourPos.z += neighbour.z - position.z; 136 } 137 } 138 139 if (neighbourCount > 0) { 140 averageNeighbourPos.x /= neighbourCount; 141 averageNeighbourPos.z /= neighbourCount; 142 double length = averageNeighbourPos.getLength(); 143 144 if (length > 0) { 145 averageNeighbourPos.normalize(); 146 147 position.moveAway(averageNeighbourPos); 148 } else { 149 position.randomize(random, minX, minZ, maxX, maxZ); 150 } 151 152 hasCollisions = true; 153 } 154 155 if (position.clamp(minX, minZ, maxX, maxZ)) { 156 hasCollisions = true; 157 } 158 } 159 160 if (!hasCollisions) { 161 for (Position position : positions) { 162 if (!position.isSafe(level)) { 163 position.randomize(random, minX, minZ, maxX, maxZ); 164 hasCollisions = true; 165 } 166 } 167 } 168 } 169 170 if (iteration >= MAX_ITERATION_COUNT) { 171 throw new CommandException("commands.spreadplayers.failure." + (respectTeams ? "teams" : "players"), positions.length, center.x, center.z, String.format("%.2f", minDistance)); 172 } 173 174 return iteration; 175 } 176 177 private double setPlayerPositions(List<LivingEntity> players, Level level, Position[] positions, boolean respectTeams) { 178 double avgDistance = 0; 179 int positionIndex = 0; 180 Map<Team, Position> teamPositions = Maps.newHashMap(); 181 182 for (int i = 0; i < players.size(); i++) { 183 LivingEntity player = players.get(i); 184 Position position; 185 186 if (respectTeams) { 187 Team team = player instanceof Player ? ((Player) player).getTeam() : null; 188 189 if (!teamPositions.containsKey(team)) { 190 teamPositions.put(team, positions[positionIndex++]); 191 } 192 193 position = teamPositions.get(team); 194 } else { 195 position = positions[positionIndex++]; 196 } 197 198 player.teleportTo(Mth.floor(position.x) + 0.5f, position.getSpawnY(level), Mth.floor(position.z) + 0.5); 199 200 double closest = Double.MAX_VALUE; 201 for (int j = 0; j < positions.length; j++) { 202 if (position == positions[j]) continue; 203 204 double dist = position.dist(positions[j]); 205 closest = Math.min(dist, closest); 206 } 207 avgDistance += closest; 208 } 209 210 avgDistance /= players.size(); 211 return avgDistance; 212 } 213 214 private Position[] createInitialPositions(Random random, int count, double minX, double minZ, double maxX, double maxZ) { 215 Position[] result = new Position[count]; 216 217 for (int i = 0; i < result.length; i++) { 218 Position position = new Position(); 219 220 position.randomize(random, minX, minZ, maxX, maxZ); 221 222 result[i] = position; 223 } 224 225 return result; 226 } 227 228 private static class Position { 229 double x; 230 double z; 231 232 Position() { 233 } 234 235 Position(double x, double z) { 236 this.x = x; 237 this.z = z; 238 } 239 240 void set(double x, double z) { 241 this.x = x; 242 this.z = z; 243 } 244 245 double dist(Position target) { 246 double dx = x - target.x; 247 double dz = z - target.z; 248 249 return Math.sqrt(dx * dx + dz * dz); 250 } 251 252 void normalize() { 253 double dist = (double) getLength(); 254 x /= dist; 255 z /= dist; 256 } 257 258 float getLength() { 259 return Mth.sqrt(x * x + z * z); 260 } 261 262 public void moveAway(Position pos) { 263 x -= pos.x; 264 z -= pos.z; 265 } 266 267 public boolean clamp(double minX, double minZ, double maxX, double maxZ) { 268 boolean changed = false; 269 270 if (x < minX) { 271 x = minX; 272 changed = true; 273 } else if (x > maxX) { 274 x = maxX; 275 changed = true; 276 } 277 278 if (z < minZ) { 279 z = minZ; 280 changed = true; 281 } else if (z > maxZ) { 282 z = maxZ; 283 changed = true; 284 } 285 286 return changed; 287 } 288 289 public int getSpawnY(Level level) { 290 int xt = Mth.floor(x); 291 int zt = Mth.floor(z); 292 293 for (int y = Level.maxBuildHeight; y > 0; y--) { 294 int tile = level.getTile(xt, y, zt); 295 296 if (tile != 0) { 297 return y + 1; 298 } 299 } 300 301 return Level.maxBuildHeight + 1; 302 } 303 304 public boolean isSafe(Level level) { 305 int xt = Mth.floor(x); 306 int zt = Mth.floor(z); 307 308 for (int y = Level.maxBuildHeight; y > 0; y--) { 309 int tile = level.getTile(xt, y, zt); 310 311 if (tile != 0) { 312 Material material = Tile.tiles[tile].material; 313 314 return !material.isLiquid() && material != Material.fire; 315 } 316 } 317 318 return false; 319 } 320 321 public void randomize(Random random, double minX, double minZ, double maxX, double maxZ) { 322 x = Mth.nextDouble(random, minX, maxX); 323 z = Mth.nextDouble(random, minZ, maxZ); 324 } 325 } 326} 327 328*/