Bukkit-API  1.7.9-R0.2
The inofficial Bukkit-API
SpreadPlayersCommand.java
1 package org.bukkit.command.defaults;
2 
3 import com.google.common.collect.Lists;
4 import com.google.common.collect.Maps;
5 import com.google.common.collect.Sets;
6 import java.util.List;
7 import java.util.Map;
8 import java.util.Random;
9 import java.util.Set;
10 
11 import org.bukkit.Bukkit;
12 import org.bukkit.ChatColor;
13 import org.bukkit.Location;
14 import org.bukkit.World;
16 import org.bukkit.entity.Player;
17 import org.bukkit.scoreboard.Team;
18 
19 public class SpreadPlayersCommand extends VanillaCommand {
20  private static final Random random = new Random();
21 
22  public SpreadPlayersCommand() {
23  super("spreadplayers");
24  this.description = "Spreads players around a point";
25  this.usageMessage = "/spreadplayers <x> <z> <spreadDistance> <maxRange> <respectTeams true|false> <player ...>";
26  this.setPermission("bukkit.command.spreadplayers");
27  }
28 
29  @Override
30  public boolean execute(CommandSender sender, String commandLabel, String[] args) {
31  if (!testPermission(sender)) {
32  return true;
33  }
34 
35  if (args.length < 6) {
36  sender.sendMessage(ChatColor.RED + "Usage: " + usageMessage);
37  return false;
38  }
39 
40  final double x = getDouble(sender, args[0], -30000000, 30000000);
41  final double z = getDouble(sender, args[1], -30000000, 30000000);
42  final double distance = getDouble(sender, args[2]);
43  final double range = getDouble(sender, args[3]);
44 
45  if (distance < 0.0D) {
46  sender.sendMessage(ChatColor.RED + "Distance is too small.");
47  return false;
48  }
49 
50  if (range < distance + 1.0D) {
51  sender.sendMessage(ChatColor.RED + "Max range is too small.");
52  return false;
53  }
54 
55  final String respectTeams = args[4];
56  boolean teams = false;
57 
58  if (respectTeams.equalsIgnoreCase("true")) {
59  teams = true;
60  } else if (!respectTeams.equalsIgnoreCase("false")) {
61  sender.sendMessage(String.format(ChatColor.RED + "'%s' is not true or false", args[4]));
62  return false;
63  }
64 
65  List<Player> players = Lists.newArrayList();
66  World world = null;
67 
68  for (int i = 5; i < args.length; i++) {
69  Player player = Bukkit.getPlayerExact(args[i]);
70  if (player == null) {
71  continue;
72  }
73 
74  if (world == null) {
75  world = player.getWorld();
76  }
77  players.add(player);
78  }
79 
80  if (world == null) {
81  return true;
82  }
83 
84  final double xRangeMin = x - range;
85  final double zRangeMin = z - range;
86  final double xRangeMax = x + range;
87  final double zRangeMax = z + range;
88 
89  final int spreadSize = teams ? getTeams(players) : players.size();
90 
91  final Location[] locations = getSpreadLocations(world, spreadSize, xRangeMin, zRangeMin, xRangeMax, zRangeMax);
92  final int rangeSpread = range(world, distance, xRangeMin, zRangeMin, xRangeMax, zRangeMax, locations);
93 
94  if (rangeSpread == -1) {
95  sender.sendMessage(String.format("Could not spread %d %s around %s,%s (too many players for space - try using spread of at most %s)", spreadSize, teams ? "teams" : "players", x, z));
96  return false;
97  }
98 
99  final double distanceSpread = spread(world, players, locations, teams);
100 
101  sender.sendMessage(String.format("Succesfully spread %d %s around %s,%s", locations.length, teams ? "teams" : "players", x, z));
102  if (locations.length > 1) {
103  sender.sendMessage(String.format("(Average distance between %s is %s blocks apart after %s iterations)", teams ? "teams" : "players", String.format("%.2f", distanceSpread), rangeSpread));
104  }
105  return true;
106  }
107 
108  private int range(World world, double distance, double xRangeMin, double zRangeMin, double xRangeMax, double zRangeMax, Location[] locations) {
109  boolean flag = true;
110  double max;
111 
112  int i;
113 
114  for (i = 0; i < 10000 && flag; ++i) {
115  flag = false;
116  max = Float.MAX_VALUE;
117 
118  Location loc1;
119  int j;
120 
121  for (int k = 0; k < locations.length; ++k) {
122  Location loc2 = locations[k];
123 
124  j = 0;
125  loc1 = new Location(world, 0, 0, 0);
126 
127  for (int l = 0; l < locations.length; ++l) {
128  if (k != l) {
129  Location loc3 = locations[l];
130  double dis = loc2.distanceSquared(loc3);
131 
132  max = Math.min(dis, max);
133  if (dis < distance) {
134  ++j;
135  loc1.add(loc3.getX() - loc2.getX(), 0, 0);
136  loc1.add(loc3.getZ() - loc2.getZ(), 0, 0);
137  }
138  }
139  }
140 
141  if (j > 0) {
142  loc2.setX(loc2.getX() / j);
143  loc2.setZ(loc2.getZ() / j);
144  double d7 = Math.sqrt(loc1.getX() * loc1.getX() + loc1.getZ() * loc1.getZ());
145 
146  if (d7 > 0.0D) {
147  loc1.setX(loc1.getX() / d7);
148  loc2.add(-loc1.getX(), 0, -loc1.getZ());
149  } else {
150  double x = xRangeMin >= xRangeMax ? xRangeMin : random.nextDouble() * (xRangeMax - xRangeMin) + xRangeMin;
151  double z = zRangeMin >= zRangeMax ? zRangeMin : random.nextDouble() * (zRangeMax - zRangeMin) + zRangeMin;
152  loc2.setX(x);
153  loc2.setZ(z);
154  }
155 
156  flag = true;
157  }
158 
159  boolean swap = false;
160 
161  if (loc2.getX() < xRangeMin) {
162  loc2.setX(xRangeMin);
163  swap = true;
164  } else if (loc2.getX() > xRangeMax) {
165  loc2.setX(xRangeMax);
166  swap = true;
167  }
168 
169  if (loc2.getZ() < zRangeMin) {
170  loc2.setZ(zRangeMin);
171  swap = true;
172  } else if (loc2.getZ() > zRangeMax) {
173  loc2.setZ(zRangeMax);
174  swap = true;
175  }
176  if (swap) {
177  flag = true;
178  }
179  }
180 
181  if (!flag) {
182  Location[] locs = locations;
183  int i1 = locations.length;
184 
185  for (j = 0; j < i1; ++j) {
186  loc1 = locs[j];
187  if (world.getHighestBlockYAt(loc1) == 0) {
188  double x = xRangeMin >= xRangeMax ? xRangeMin : random.nextDouble() * (xRangeMax - xRangeMin) + xRangeMin;
189  double z = zRangeMin >= zRangeMax ? zRangeMin : random.nextDouble() * (zRangeMax - zRangeMin) + zRangeMin;
190  locations[i] = (new Location(world, x, 0, z));
191  loc1.setX(x);
192  loc1.setZ(z);
193  flag = true;
194  }
195  }
196  }
197  }
198 
199  if (i >= 10000) {
200  return -1;
201  } else {
202  return i;
203  }
204  }
205 
206  private double spread(World world, List<Player> list, Location[] locations, boolean teams) {
207  double distance = 0.0D;
208  int i = 0;
209  Map<Team, Location> hashmap = Maps.newHashMap();
210 
211  for (int j = 0; j < list.size(); ++j) {
212  Player player = list.get(j);
213  Location location;
214 
215  if (teams) {
216  Team team = player.getScoreboard().getPlayerTeam(player);
217 
218  if (!hashmap.containsKey(team)) {
219  hashmap.put(team, locations[i++]);
220  }
221 
222  location = hashmap.get(team);
223  } else {
224  location = locations[i++];
225  }
226 
227  player.teleport(new Location(world, Math.floor(location.getX()) + 0.5D, world.getHighestBlockYAt((int) location.getX(), (int) location.getZ()), Math.floor(location.getZ()) + 0.5D));
228  double value = Double.MAX_VALUE;
229 
230  for (int k = 0; k < locations.length; ++k) {
231  if (location != locations[k]) {
232  double d = location.distanceSquared(locations[k]);
233  value = Math.min(d, value);
234  }
235  }
236 
237  distance += value;
238  }
239 
240  distance /= list.size();
241  return distance;
242  }
243 
244  private int getTeams(List<Player> players) {
245  Set<Team> teams = Sets.newHashSet();
246 
247  for (Player player : players) {
248  teams.add(player.getScoreboard().getPlayerTeam(player));
249  }
250 
251  return teams.size();
252  }
253 
254  private Location[] getSpreadLocations(World world, int size, double xRangeMin, double zRangeMin, double xRangeMax, double zRangeMax) {
255  Location[] locations = new Location[size];
256 
257  for (int i = 0; i < size; ++i) {
258  double x = xRangeMin >= xRangeMax ? xRangeMin : random.nextDouble() * (xRangeMax - xRangeMin) + xRangeMin;
259  double z = zRangeMin >= zRangeMax ? zRangeMin : random.nextDouble() * (zRangeMax - zRangeMin) + zRangeMin;
260  locations[i] = (new Location(world, x, 0, z));
261  }
262 
263  return locations;
264  }
265 }
boolean testPermission(CommandSender target)
boolean teleport(Location location)
void setX(double x)
Definition: Location.java:90
Scoreboard getScoreboard()
void sendMessage(String message)
Location add(Location vec)
Definition: Location.java:301
Team getPlayerTeam(OfflinePlayer player)
double distanceSquared(Location o)
Definition: Location.java:442
void setPermission(String permission)
static Player getPlayerExact(String name)
Definition: Bukkit.java:436
int getHighestBlockYAt(int x, int z)
void setZ(double z)
Definition: Location.java:146