the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
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*/