PageRenderTime 35ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/worldguard-legacy/src/main/java/com/sk89q/worldguard/bukkit/WorldGuardPlugin.java

https://gitlab.com/igserfurtmcschulserver/CustomWorldGuard
Java | 1060 lines | 604 code | 125 blank | 331 comment | 108 complexity | 8954b8cbef1881cc9601feb32effb26c MD5 | raw file
  1. /*
  2. * WorldGuard, a suite of tools for Minecraft
  3. * Copyright (C) sk89q <http://www.sk89q.com>
  4. * Copyright (C) WorldGuard team and contributors
  5. *
  6. * This program is free software: you can redistribute it and/or modify it
  7. * under the terms of the GNU Lesser General Public License as published by the
  8. * Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful, but WITHOUT
  12. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  14. * for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. package com.sk89q.worldguard.bukkit;
  20. import com.google.common.collect.ImmutableList;
  21. import com.google.common.collect.Lists;
  22. import com.google.common.util.concurrent.Futures;
  23. import com.google.common.util.concurrent.ListeningExecutorService;
  24. import com.google.common.util.concurrent.MoreExecutors;
  25. import com.sk89q.bukkit.util.CommandsManagerRegistration;
  26. import com.sk89q.minecraft.util.commands.*;
  27. import com.sk89q.squirrelid.cache.HashMapCache;
  28. import com.sk89q.squirrelid.cache.ProfileCache;
  29. import com.sk89q.squirrelid.cache.SQLiteCache;
  30. import com.sk89q.squirrelid.resolver.*;
  31. import com.sk89q.wepif.PermissionsResolverManager;
  32. import com.sk89q.worldedit.bukkit.WorldEditPlugin;
  33. import com.sk89q.worldguard.LocalPlayer;
  34. import com.sk89q.worldguard.bukkit.commands.GeneralCommands;
  35. import com.sk89q.worldguard.bukkit.commands.ProtectionCommands;
  36. import com.sk89q.worldguard.bukkit.commands.ToggleCommands;
  37. import com.sk89q.worldguard.bukkit.event.player.ProcessPlayerEvent;
  38. import com.sk89q.worldguard.bukkit.listener.BlacklistListener;
  39. import com.sk89q.worldguard.bukkit.listener.BlockedPotionsListener;
  40. import com.sk89q.worldguard.bukkit.listener.BuildPermissionListener;
  41. import com.sk89q.worldguard.bukkit.listener.ChestProtectionListener;
  42. import com.sk89q.worldguard.bukkit.listener.DebuggingListener;
  43. import com.sk89q.worldguard.bukkit.listener.EventAbstractionListener;
  44. import com.sk89q.worldguard.bukkit.listener.InvincibilityListener;
  45. import com.sk89q.worldguard.bukkit.listener.PlayerModesListener;
  46. import com.sk89q.worldguard.bukkit.listener.PlayerMoveListener;
  47. import com.sk89q.worldguard.bukkit.listener.RegionFlagsListener;
  48. import com.sk89q.worldguard.bukkit.listener.RegionProtectionListener;
  49. import com.sk89q.worldguard.bukkit.listener.WorldGuardBlockListener;
  50. import com.sk89q.worldguard.bukkit.listener.WorldGuardCommandBookListener;
  51. import com.sk89q.worldguard.bukkit.listener.WorldGuardEntityListener;
  52. import com.sk89q.worldguard.bukkit.listener.WorldGuardHangingListener;
  53. import com.sk89q.worldguard.bukkit.listener.WorldGuardPlayerListener;
  54. import com.sk89q.worldguard.bukkit.listener.WorldGuardServerListener;
  55. import com.sk89q.worldguard.bukkit.listener.WorldGuardVehicleListener;
  56. import com.sk89q.worldguard.bukkit.listener.WorldGuardWeatherListener;
  57. import com.sk89q.worldguard.bukkit.listener.WorldGuardWorldListener;
  58. import com.sk89q.worldguard.bukkit.listener.WorldRulesListener;
  59. import com.sk89q.worldguard.bukkit.util.Events;
  60. import com.sk89q.worldguard.protection.GlobalRegionManager;
  61. import com.sk89q.worldguard.protection.flags.DefaultFlag;
  62. import com.sk89q.worldguard.protection.flags.Flag;
  63. import com.sk89q.worldguard.protection.flags.registry.FlagRegistry;
  64. import com.sk89q.worldguard.protection.flags.registry.SimpleFlagRegistry;
  65. import com.sk89q.worldguard.protection.managers.RegionManager;
  66. import com.sk89q.worldguard.protection.managers.storage.StorageException;
  67. import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
  68. import com.sk89q.worldguard.protection.regions.ProtectedRegion;
  69. import com.sk89q.worldguard.protection.util.UnresolvedNamesException;
  70. import com.sk89q.worldguard.session.SessionManager;
  71. import com.sk89q.worldguard.util.concurrent.EvenMoreExecutors;
  72. import com.sk89q.worldguard.util.logging.ClassSourceValidator;
  73. import com.sk89q.worldguard.util.logging.RecordMessagePrefixer;
  74. import com.sk89q.worldguard.util.task.SimpleSupervisor;
  75. import com.sk89q.worldguard.util.task.Supervisor;
  76. import com.sk89q.worldguard.util.task.Task;
  77. import org.bukkit.ChatColor;
  78. import org.bukkit.Location;
  79. import org.bukkit.OfflinePlayer;
  80. import org.bukkit.World;
  81. import org.bukkit.World.Environment;
  82. import org.bukkit.block.Block;
  83. import org.bukkit.command.Command;
  84. import org.bukkit.command.CommandSender;
  85. import org.bukkit.command.ConsoleCommandSender;
  86. import org.bukkit.entity.Player;
  87. import org.bukkit.permissions.Permissible;
  88. import org.bukkit.plugin.Plugin;
  89. import org.bukkit.plugin.java.JavaPlugin;
  90. import javax.annotation.Nullable;
  91. import java.io.File;
  92. import java.io.FileNotFoundException;
  93. import java.io.FileOutputStream;
  94. import java.io.IOException;
  95. import java.io.InputStream;
  96. import java.util.ArrayList;
  97. import java.util.Arrays;
  98. import java.util.Collection;
  99. import java.util.Iterator;
  100. import java.util.List;
  101. import java.util.Set;
  102. import java.util.concurrent.CancellationException;
  103. import java.util.concurrent.ExecutionException;
  104. import java.util.concurrent.RejectedExecutionException;
  105. import java.util.concurrent.TimeUnit;
  106. import java.util.jar.JarFile;
  107. import java.util.logging.Level;
  108. import java.util.logging.Logger;
  109. import java.util.zip.ZipEntry;
  110. /**
  111. * The main class for WorldGuard as a Bukkit plugin.
  112. */
  113. public class WorldGuardPlugin extends JavaPlugin {
  114. private static final Logger log = Logger.getLogger(WorldGuardPlugin.class.getCanonicalName());
  115. private static WorldGuardPlugin inst;
  116. private final CommandsManager<CommandSender> commands;
  117. private final ConfigurationManager configuration = new ConfigurationManager(this);
  118. private final RegionContainer regionContainer = new RegionContainer(this);
  119. private final GlobalRegionManager globalRegionManager = new GlobalRegionManager(this, regionContainer);
  120. private final SimpleFlagRegistry flagRegistry = new SimpleFlagRegistry();
  121. private SessionManager sessionManager;
  122. private final Supervisor supervisor = new SimpleSupervisor();
  123. private ListeningExecutorService executorService;
  124. private ProfileService profileService;
  125. private ProfileCache profileCache;
  126. private PlayerMoveListener playerMoveListener;
  127. /**
  128. * Construct objects. Actual loading occurs when the plugin is enabled, so
  129. * this merely instantiates the objects.
  130. */
  131. public WorldGuardPlugin() {
  132. final WorldGuardPlugin plugin = inst = this;
  133. commands = new CommandsManager<CommandSender>() {
  134. @Override
  135. public boolean hasPermission(CommandSender player, String perm) {
  136. return plugin.hasPermission(player, perm);
  137. }
  138. };
  139. flagRegistry.registerAll(DefaultFlag.getDefaultFlags());
  140. }
  141. /**
  142. * Get the current instance of WorldGuard
  143. * @return WorldGuardPlugin instance
  144. */
  145. public static WorldGuardPlugin inst() {
  146. return inst;
  147. }
  148. /**
  149. * Called on plugin enable.
  150. */
  151. @Override
  152. @SuppressWarnings("deprecation")
  153. public void onEnable() {
  154. configureLogger();
  155. flagRegistry.setInitialized(true);
  156. getDataFolder().mkdirs(); // Need to create the plugins/WorldGuard folder
  157. executorService = MoreExecutors.listeningDecorator(EvenMoreExecutors.newBoundedCachedThreadPool(0, 1, 20));
  158. sessionManager = new SessionManager(this);
  159. // Set the proper command injector
  160. commands.setInjector(new SimpleInjector(this));
  161. // Catch bad things being done by naughty plugins that include
  162. // WorldGuard's classes
  163. ClassSourceValidator verifier = new ClassSourceValidator(this);
  164. verifier.reportMismatches(ImmutableList.of(WGBukkit.class, ProtectedRegion.class, ProtectedCuboidRegion.class, Flag.class));
  165. // Register command classes
  166. final CommandsManagerRegistration reg = new CommandsManagerRegistration(this, commands);
  167. reg.register(ToggleCommands.class);
  168. reg.register(ProtectionCommands.class);
  169. getServer().getScheduler().scheduleSyncDelayedTask(this, new Runnable() {
  170. @Override
  171. public void run() {
  172. if (!getGlobalStateManager().hasCommandBookGodMode()) {
  173. reg.register(GeneralCommands.class);
  174. }
  175. }
  176. }, 0L);
  177. File cacheDir = new File(getDataFolder(), "cache");
  178. cacheDir.mkdirs();
  179. try {
  180. profileCache = new SQLiteCache(new File(cacheDir, "profiles.sqlite"));
  181. } catch (IOException e) {
  182. log.log(Level.WARNING, "Failed to initialize SQLite profile cache");
  183. profileCache = new HashMapCache();
  184. }
  185. profileService = new CacheForwardingService(
  186. new CombinedProfileService(
  187. BukkitPlayerService.getInstance(),
  188. HttpRepositoryService.forMinecraft()),
  189. profileCache);
  190. PermissionsResolverManager.initialize(this);
  191. configuration.load();
  192. log.info("Loading region data...");
  193. regionContainer.initialize();
  194. getServer().getScheduler().scheduleSyncRepeatingTask(this, sessionManager, SessionManager.RUN_DELAY, SessionManager.RUN_DELAY);
  195. // Register events
  196. getServer().getPluginManager().registerEvents(sessionManager, this);
  197. (new WorldGuardPlayerListener(this)).registerEvents();
  198. (new WorldGuardBlockListener(this)).registerEvents();
  199. (new WorldGuardEntityListener(this)).registerEvents();
  200. (new WorldGuardWeatherListener(this)).registerEvents();
  201. (new WorldGuardVehicleListener(this)).registerEvents();
  202. (new WorldGuardServerListener(this)).registerEvents();
  203. (new WorldGuardHangingListener(this)).registerEvents();
  204. // Modules
  205. (playerMoveListener = new PlayerMoveListener(this)).registerEvents();
  206. (new BlacklistListener(this)).registerEvents();
  207. (new ChestProtectionListener(this)).registerEvents();
  208. (new RegionProtectionListener(this)).registerEvents();
  209. (new RegionFlagsListener(this)).registerEvents();
  210. (new WorldRulesListener(this)).registerEvents();
  211. (new BlockedPotionsListener(this)).registerEvents();
  212. (new EventAbstractionListener(this)).registerEvents();
  213. (new PlayerModesListener(this)).registerEvents();
  214. (new BuildPermissionListener(this)).registerEvents();
  215. (new InvincibilityListener(this)).registerEvents();
  216. if ("true".equalsIgnoreCase(System.getProperty("worldguard.debug.listener"))) {
  217. (new DebuggingListener(this, log)).registerEvents();
  218. }
  219. configuration.updateCommandBookGodMode();
  220. if (getServer().getPluginManager().isPluginEnabled("CommandBook")) {
  221. getServer().getPluginManager().registerEvents(new WorldGuardCommandBookListener(this), this);
  222. }
  223. // handle worlds separately to initialize already loaded worlds
  224. WorldGuardWorldListener worldListener = (new WorldGuardWorldListener(this));
  225. for (World world : getServer().getWorlds()) {
  226. worldListener.initWorld(world);
  227. }
  228. worldListener.registerEvents();
  229. for (Player player : BukkitUtil.getOnlinePlayers()) {
  230. ProcessPlayerEvent event = new ProcessPlayerEvent(player);
  231. Events.fire(event);
  232. }
  233. }
  234. @Override
  235. public void onDisable() {
  236. executorService.shutdown();
  237. try {
  238. log.log(Level.INFO, "Shutting down executor and waiting for any pending tasks...");
  239. List<Task<?>> tasks = supervisor.getTasks();
  240. if (!tasks.isEmpty()) {
  241. StringBuilder builder = new StringBuilder("Known tasks:");
  242. for (Task<?> task : tasks) {
  243. builder.append("\n");
  244. builder.append(task.getName());
  245. }
  246. log.log(Level.INFO, builder.toString());
  247. }
  248. Futures.successfulAsList(tasks).get();
  249. executorService.awaitTermination(Integer.MAX_VALUE, TimeUnit.DAYS);
  250. } catch (InterruptedException e) {
  251. Thread.currentThread().interrupt();
  252. } catch (ExecutionException e) {
  253. log.log(Level.WARNING, "Some tasks failed while waiting for remaining tasks to finish", e);
  254. }
  255. regionContainer.unload();
  256. configuration.unload();
  257. this.getServer().getScheduler().cancelTasks(this);
  258. }
  259. @Override
  260. public boolean onCommand(CommandSender sender, Command cmd, String label, String[] args) {
  261. try {
  262. commands.execute(cmd.getName(), args, sender, sender);
  263. } catch (CommandPermissionsException e) {
  264. sender.sendMessage(ChatColor.RED + "You don't have permission.");
  265. } catch (MissingNestedCommandException e) {
  266. sender.sendMessage(ChatColor.RED + e.getUsage());
  267. } catch (CommandUsageException e) {
  268. sender.sendMessage(ChatColor.RED + e.getMessage());
  269. sender.sendMessage(ChatColor.RED + e.getUsage());
  270. } catch (WrappedCommandException e) {
  271. sender.sendMessage(ChatColor.RED + convertThrowable(e.getCause()));
  272. } catch (CommandException e) {
  273. sender.sendMessage(ChatColor.RED + e.getMessage());
  274. }
  275. return true;
  276. }
  277. /**
  278. * Convert the throwable into a somewhat friendly message.
  279. *
  280. * @param throwable the throwable
  281. * @return a message
  282. */
  283. public String convertThrowable(@Nullable Throwable throwable) {
  284. if (throwable instanceof NumberFormatException) {
  285. return "Number expected, string received instead.";
  286. } else if (throwable instanceof StorageException) {
  287. log.log(Level.WARNING, "Error loading/saving regions", throwable);
  288. return "Region data could not be loaded/saved: " + throwable.getMessage();
  289. } else if (throwable instanceof RejectedExecutionException) {
  290. return "There are currently too many tasks queued to add yours. Use /wg running to list queued and running tasks.";
  291. } else if (throwable instanceof CancellationException) {
  292. return "WorldGuard: Task was cancelled";
  293. } else if (throwable instanceof InterruptedException) {
  294. return "WorldGuard: Task was interrupted";
  295. } else if (throwable instanceof UnresolvedNamesException) {
  296. return throwable.getMessage();
  297. } else if (throwable instanceof CommandException) {
  298. return throwable.getMessage();
  299. } else {
  300. log.log(Level.WARNING, "WorldGuard encountered an unexpected error", throwable);
  301. return "WorldGuard: An unexpected error occurred! Please see the server console.";
  302. }
  303. }
  304. /**
  305. * Get the GlobalRegionManager.
  306. *
  307. * @return the plugin's global region manager
  308. * @deprecated use {@link #getRegionContainer()}
  309. */
  310. @Deprecated
  311. public GlobalRegionManager getGlobalRegionManager() {
  312. return globalRegionManager;
  313. }
  314. /**
  315. * Get the object that manages region data.
  316. *
  317. * @return the region container
  318. */
  319. public RegionContainer getRegionContainer() {
  320. return regionContainer;
  321. }
  322. /**
  323. * Get the WorldGuard Configuration.
  324. *
  325. * @return ConfigurationManager
  326. * @deprecated Use {@link #getGlobalStateManager()} instead
  327. */
  328. @Deprecated
  329. public ConfigurationManager getGlobalConfiguration() {
  330. return getGlobalStateManager();
  331. }
  332. /**
  333. * Gets the flag state manager.
  334. *
  335. * @return The flag state manager
  336. */
  337. public SessionManager getSessionManager() {
  338. return sessionManager;
  339. }
  340. /**
  341. * Get the global ConfigurationManager.
  342. * USe this to access global configuration values and per-world configuration values.
  343. * @return The global ConfigurationManager
  344. */
  345. public ConfigurationManager getGlobalStateManager() {
  346. return configuration;
  347. }
  348. /**
  349. * Get the supervisor.
  350. *
  351. * @return the supervisor
  352. */
  353. public Supervisor getSupervisor() {
  354. return supervisor;
  355. }
  356. /**
  357. * Get the global executor service for internal usage (please use your
  358. * own executor service).
  359. *
  360. * @return the global executor service
  361. */
  362. public ListeningExecutorService getExecutorService() {
  363. return executorService;
  364. }
  365. /**
  366. * Get the profile lookup service.
  367. *
  368. * @return the profile lookup service
  369. */
  370. public ProfileService getProfileService() {
  371. return profileService;
  372. }
  373. /**
  374. * Get the profile cache.
  375. *
  376. * @return the profile cache
  377. */
  378. public ProfileCache getProfileCache() {
  379. return profileCache;
  380. }
  381. /**
  382. * Get the flag registry.
  383. *
  384. * @return the flag registry
  385. */
  386. public FlagRegistry getFlagRegistry() {
  387. return flagRegistry;
  388. }
  389. /**
  390. * Check whether a player is in a group.
  391. * This calls the corresponding method in PermissionsResolverManager
  392. *
  393. * @param player The player to check
  394. * @param group The group
  395. * @return whether {@code player} is in {@code group}
  396. */
  397. public boolean inGroup(Player player, String group) {
  398. try {
  399. return PermissionsResolverManager.getInstance().inGroup(player, group);
  400. } catch (Throwable t) {
  401. t.printStackTrace();
  402. return false;
  403. }
  404. }
  405. /**
  406. * Get the groups of a player.
  407. * This calls the corresponding method in PermissionsResolverManager.
  408. * @param player The player to check
  409. * @return The names of each group the playe is in.
  410. */
  411. public String[] getGroups(Player player) {
  412. try {
  413. return PermissionsResolverManager.getInstance().getGroups(player);
  414. } catch (Throwable t) {
  415. t.printStackTrace();
  416. return new String[0];
  417. }
  418. }
  419. /**
  420. * Gets the name of a command sender. This is a unique name and this
  421. * method should never return a "display name".
  422. *
  423. * @param sender The sender to get the name of
  424. * @return The unique name of the sender.
  425. */
  426. public String toUniqueName(CommandSender sender) {
  427. if (sender instanceof ConsoleCommandSender) {
  428. return "*Console*";
  429. } else {
  430. return sender.getName();
  431. }
  432. }
  433. /**
  434. * Gets the name of a command sender. This play be a display name.
  435. *
  436. * @param sender The CommandSender to get the name of.
  437. * @return The name of the given sender
  438. */
  439. public String toName(CommandSender sender) {
  440. if (sender instanceof ConsoleCommandSender) {
  441. return "*Console*";
  442. } else if (sender instanceof Player) {
  443. return ((Player) sender).getDisplayName();
  444. } else {
  445. return sender.getName();
  446. }
  447. }
  448. /**
  449. * Checks permissions.
  450. *
  451. * @param sender The sender to check the permission on.
  452. * @param perm The permission to check the permission on.
  453. * @return whether {@code sender} has {@code perm}
  454. */
  455. public boolean hasPermission(CommandSender sender, String perm) {
  456. if (sender.isOp()) {
  457. if (sender instanceof Player) {
  458. if (this.getGlobalStateManager().get(((Player) sender).
  459. getWorld()).opPermissions) {
  460. return true;
  461. }
  462. } else {
  463. return true;
  464. }
  465. }
  466. // Invoke the permissions resolver
  467. if (sender instanceof Player) {
  468. Player player = (Player) sender;
  469. return PermissionsResolverManager.getInstance().hasPermission(player.getWorld().getName(), player, perm);
  470. }
  471. return false;
  472. }
  473. /**
  474. * Checks permissions and throws an exception if permission is not met.
  475. *
  476. * @param sender The sender to check the permission on.
  477. * @param perm The permission to check the permission on.
  478. * @throws CommandPermissionsException if {@code sender} doesn't have {@code perm}
  479. */
  480. public void checkPermission(CommandSender sender, String perm)
  481. throws CommandPermissionsException {
  482. if (!hasPermission(sender, perm)) {
  483. throw new CommandPermissionsException();
  484. }
  485. }
  486. /**
  487. * Checks to see if the sender is a player, otherwise throw an exception.
  488. *
  489. * @param sender The {@link CommandSender} to check
  490. * @return {@code sender} casted to a player
  491. * @throws CommandException if {@code sender} isn't a {@link Player}
  492. */
  493. public Player checkPlayer(CommandSender sender)
  494. throws CommandException {
  495. if (sender instanceof Player) {
  496. return (Player) sender;
  497. } else {
  498. throw new CommandException("A player is expected.");
  499. }
  500. }
  501. /**
  502. * Match player names.
  503. *
  504. * The filter string uses the following format:
  505. * @[name] looks up all players with the exact {@code name}
  506. * *[name] matches any player whose name contains {@code name}
  507. * [name] matches any player whose name starts with {@code name}
  508. *
  509. * @param filter The filter string to check.
  510. * @return A {@link List} of players who match {@code filter}
  511. */
  512. public List<Player> matchPlayerNames(String filter) {
  513. Collection<? extends Player> players = BukkitUtil.getOnlinePlayers();
  514. filter = filter.toLowerCase();
  515. // Allow exact name matching
  516. if (filter.charAt(0) == '@' && filter.length() >= 2) {
  517. filter = filter.substring(1);
  518. for (Player player : players) {
  519. if (player.getName().equalsIgnoreCase(filter)) {
  520. List<Player> list = new ArrayList<Player>();
  521. list.add(player);
  522. return list;
  523. }
  524. }
  525. return new ArrayList<Player>();
  526. // Allow partial name matching
  527. } else if (filter.charAt(0) == '*' && filter.length() >= 2) {
  528. filter = filter.substring(1);
  529. List<Player> list = new ArrayList<Player>();
  530. for (Player player : players) {
  531. if (player.getName().toLowerCase().contains(filter)) {
  532. list.add(player);
  533. }
  534. }
  535. return list;
  536. // Start with name matching
  537. } else {
  538. List<Player> list = new ArrayList<Player>();
  539. for (Player player : players) {
  540. if (player.getName().toLowerCase().startsWith(filter)) {
  541. list.add(player);
  542. }
  543. }
  544. return list;
  545. }
  546. }
  547. /**
  548. * Checks if the given list of players is greater than size 0, otherwise
  549. * throw an exception.
  550. *
  551. * @param players The {@link List} to check
  552. * @return {@code players} as an {@link Iterable}
  553. * @throws CommandException If {@code players} is empty
  554. */
  555. protected Iterable<? extends Player> checkPlayerMatch(List<? extends Player> players)
  556. throws CommandException {
  557. // Check to see if there were any matches
  558. if (players.size() == 0) {
  559. throw new CommandException("No players matched query.");
  560. }
  561. return players;
  562. }
  563. /**
  564. * Matches players based on the specified filter string
  565. *
  566. * The filter string format is as follows:
  567. * * returns all the players currently online
  568. * If {@code sender} is a {@link Player}:
  569. * #world returns all players in the world that {@code sender} is in
  570. * #near reaturns all players within 30 blocks of {@code sender}'s location
  571. * Otherwise, the format is as specified in {@link #matchPlayerNames(String)}
  572. *
  573. * @param source The CommandSender who is trying to find a player
  574. * @param filter The filter string for players
  575. * @return iterator for players
  576. * @throws CommandException if no matches are found
  577. */
  578. public Iterable<? extends Player> matchPlayers(CommandSender source, String filter)
  579. throws CommandException {
  580. if (BukkitUtil.getOnlinePlayers().isEmpty()) {
  581. throw new CommandException("No players matched query.");
  582. }
  583. if (filter.equals("*")) {
  584. return checkPlayerMatch(Lists.newArrayList(BukkitUtil.getOnlinePlayers()));
  585. }
  586. // Handle special hash tag groups
  587. if (filter.charAt(0) == '#') {
  588. // Handle #world, which matches player of the same world as the
  589. // calling source
  590. if (filter.equalsIgnoreCase("#world")) {
  591. List<Player> players = new ArrayList<Player>();
  592. Player sourcePlayer = checkPlayer(source);
  593. World sourceWorld = sourcePlayer.getWorld();
  594. for (Player player : BukkitUtil.getOnlinePlayers()) {
  595. if (player.getWorld().equals(sourceWorld)) {
  596. players.add(player);
  597. }
  598. }
  599. return checkPlayerMatch(players);
  600. // Handle #near, which is for nearby players.
  601. } else if (filter.equalsIgnoreCase("#near")) {
  602. List<Player> players = new ArrayList<Player>();
  603. Player sourcePlayer = checkPlayer(source);
  604. World sourceWorld = sourcePlayer.getWorld();
  605. org.bukkit.util.Vector sourceVector
  606. = sourcePlayer.getLocation().toVector();
  607. for (Player player : BukkitUtil.getOnlinePlayers()) {
  608. if (player.getWorld().equals(sourceWorld)
  609. && player.getLocation().toVector().distanceSquared(
  610. sourceVector) < 900) {
  611. players.add(player);
  612. }
  613. }
  614. return checkPlayerMatch(players);
  615. } else {
  616. throw new CommandException("Invalid group '" + filter + "'.");
  617. }
  618. }
  619. List<Player> players = matchPlayerNames(filter);
  620. return checkPlayerMatch(players);
  621. }
  622. /**
  623. * Match only a single player.
  624. *
  625. * @param sender The {@link CommandSender} who is requesting a player match
  626. * @param filter The filter string.
  627. * @see #matchPlayers(org.bukkit.entity.Player) for filter string syntax
  628. * @return The single player
  629. * @throws CommandException If more than one player match was found
  630. */
  631. public Player matchSinglePlayer(CommandSender sender, String filter)
  632. throws CommandException {
  633. // This will throw an exception if there are no matches
  634. Iterator<? extends Player> players = matchPlayers(sender, filter).iterator();
  635. Player match = players.next();
  636. // We don't want to match the wrong person, so fail if if multiple
  637. // players were found (we don't want to just pick off the first one,
  638. // as that may be the wrong player)
  639. if (players.hasNext()) {
  640. throw new CommandException("More than one player found! " +
  641. "Use @<name> for exact matching.");
  642. }
  643. return match;
  644. }
  645. /**
  646. * Match only a single player or console.
  647. *
  648. * The filter string syntax is as follows:
  649. * #console, *console, or ! return the server console
  650. * All syntax from {@link #matchSinglePlayer(org.bukkit.command.CommandSender, String)}
  651. * @param sender The sender trying to match a CommandSender
  652. * @param filter The filter string
  653. * @return The resulting CommandSender
  654. * @throws CommandException if either zero or more than one player matched.
  655. */
  656. public CommandSender matchPlayerOrConsole(CommandSender sender, String filter)
  657. throws CommandException {
  658. // Let's see if console is wanted
  659. if (filter.equalsIgnoreCase("#console")
  660. || filter.equalsIgnoreCase("*console*")
  661. || filter.equalsIgnoreCase("!")) {
  662. return getServer().getConsoleSender();
  663. }
  664. return matchSinglePlayer(sender, filter);
  665. }
  666. /**
  667. * Get a single player as an iterator for players.
  668. *
  669. * @param player The player to return in an Iterable
  670. * @return iterator for player
  671. */
  672. public Iterable<Player> matchPlayers(Player player) {
  673. return Arrays.asList(player);
  674. }
  675. /**
  676. * Match a world.
  677. *
  678. * The filter string syntax is as follows:
  679. * #main returns the main world
  680. * #normal returns the first world with a normal environment
  681. * #nether return the first world with a nether environment
  682. * #player:[name] returns the world that a player named {@code name} is located in, if the player is online.
  683. * [name] A world with the name {@code name}
  684. *
  685. * @param sender The sender requesting a match
  686. * @param filter The filter string
  687. * @return The resulting world
  688. * @throws CommandException if no world matches
  689. */
  690. public World matchWorld(CommandSender sender, String filter) throws CommandException {
  691. List<World> worlds = getServer().getWorlds();
  692. // Handle special hash tag groups
  693. if (filter.charAt(0) == '#') {
  694. // #main for the main world
  695. if (filter.equalsIgnoreCase("#main")) {
  696. return worlds.get(0);
  697. // #normal for the first normal world
  698. } else if (filter.equalsIgnoreCase("#normal")) {
  699. for (World world : worlds) {
  700. if (world.getEnvironment() == Environment.NORMAL) {
  701. return world;
  702. }
  703. }
  704. throw new CommandException("No normal world found.");
  705. // #nether for the first nether world
  706. } else if (filter.equalsIgnoreCase("#nether")) {
  707. for (World world : worlds) {
  708. if (world.getEnvironment() == Environment.NETHER) {
  709. return world;
  710. }
  711. }
  712. throw new CommandException("No nether world found.");
  713. // Handle getting a world from a player
  714. } else if (filter.matches("^#player$")) {
  715. String parts[] = filter.split(":", 2);
  716. // They didn't specify an argument for the player!
  717. if (parts.length == 1) {
  718. throw new CommandException("Argument expected for #player.");
  719. }
  720. return matchPlayers(sender, parts[1]).iterator().next().getWorld();
  721. } else {
  722. throw new CommandException("Invalid identifier '" + filter + "'.");
  723. }
  724. }
  725. for (World world : worlds) {
  726. if (world.getName().equals(filter)) {
  727. return world;
  728. }
  729. }
  730. throw new CommandException("No world by that exact name found.");
  731. }
  732. /**
  733. * Gets a copy of the WorldEdit plugin.
  734. *
  735. * @return The WorldEditPlugin instance
  736. * @throws CommandException If there is no WorldEditPlugin available
  737. */
  738. public WorldEditPlugin getWorldEdit() throws CommandException {
  739. Plugin worldEdit = getServer().getPluginManager().getPlugin("WorldEdit");
  740. if (worldEdit == null) {
  741. throw new CommandException("WorldEdit does not appear to be installed.");
  742. }
  743. if (worldEdit instanceof WorldEditPlugin) {
  744. return (WorldEditPlugin) worldEdit;
  745. } else {
  746. throw new CommandException("WorldEdit detection failed (report error).");
  747. }
  748. }
  749. /**
  750. * Wrap a player as a LocalPlayer.
  751. *
  752. * @param player The player to wrap
  753. * @return The wrapped player
  754. */
  755. public LocalPlayer wrapPlayer(Player player) {
  756. return new BukkitPlayer(this, player);
  757. }
  758. /**
  759. * Wrap a player as a LocalPlayer.
  760. *
  761. * @param player The player to wrap
  762. * @param silenced True to silence messages
  763. * @return The wrapped player
  764. */
  765. public LocalPlayer wrapPlayer(Player player, boolean silenced) {
  766. return new BukkitPlayer(this, player, silenced);
  767. }
  768. /**
  769. * Wrap a player as a LocalPlayer.
  770. *
  771. * <p>This implementation is incomplete -- permissions cannot be checked.</p>
  772. *
  773. * @param player The player to wrap
  774. * @return The wrapped player
  775. */
  776. public LocalPlayer wrapOfflinePlayer(OfflinePlayer player) {
  777. return new BukkitOfflinePlayer(player);
  778. }
  779. /**
  780. * Return a protection query helper object that can be used by another
  781. * plugin to test whether WorldGuard permits an action at a particular
  782. * place.
  783. *
  784. * @return an instance
  785. */
  786. public ProtectionQuery createProtectionQuery() {
  787. return new ProtectionQuery();
  788. }
  789. /**
  790. * Configure WorldGuard's loggers.
  791. */
  792. private void configureLogger() {
  793. RecordMessagePrefixer.register(Logger.getLogger("com.sk89q.worldguard"), "[WorldGuard] ");
  794. }
  795. /**
  796. * Create a default configuration file from the .jar.
  797. *
  798. * @param actual The destination file
  799. * @param defaultName The name of the file inside the jar's defaults folder
  800. */
  801. public void createDefaultConfiguration(File actual,
  802. String defaultName) {
  803. // Make parent directories
  804. File parent = actual.getParentFile();
  805. if (!parent.exists()) {
  806. parent.mkdirs();
  807. }
  808. if (actual.exists()) {
  809. return;
  810. }
  811. InputStream input =
  812. null;
  813. try {
  814. JarFile file = new JarFile(getFile());
  815. ZipEntry copy = file.getEntry("defaults/" + defaultName);
  816. if (copy == null) throw new FileNotFoundException();
  817. input = file.getInputStream(copy);
  818. } catch (IOException e) {
  819. log.severe("Unable to read default configuration: " + defaultName);
  820. }
  821. if (input != null) {
  822. FileOutputStream output = null;
  823. try {
  824. output = new FileOutputStream(actual);
  825. byte[] buf = new byte[8192];
  826. int length = 0;
  827. while ((length = input.read(buf)) > 0) {
  828. output.write(buf, 0, length);
  829. }
  830. log.info("Default configuration file written: "
  831. + actual.getAbsolutePath());
  832. } catch (IOException e) {
  833. e.printStackTrace();
  834. } finally {
  835. try {
  836. if (input != null) {
  837. input.close();
  838. }
  839. } catch (IOException ignore) {
  840. }
  841. try {
  842. if (output != null) {
  843. output.close();
  844. }
  845. } catch (IOException ignore) {
  846. }
  847. }
  848. }
  849. }
  850. /**
  851. * Notifies all with the worldguard.notify permission.
  852. * This will check both superperms and WEPIF,
  853. * but makes sure WEPIF checks don't result in duplicate notifications
  854. *
  855. * @param msg The notification to broadcast
  856. */
  857. public void broadcastNotification(String msg) {
  858. getServer().broadcast(msg, "worldguard.notify");
  859. Set<Permissible> subs = getServer().getPluginManager().getPermissionSubscriptions("worldguard.notify");
  860. for (Player player : BukkitUtil.getOnlinePlayers()) {
  861. if (!(subs.contains(player) && player.hasPermission("worldguard.notify")) &&
  862. hasPermission(player, "worldguard.notify")) { // Make sure the player wasn't already broadcasted to.
  863. player.sendMessage(msg);
  864. }
  865. }
  866. log.info(msg);
  867. }
  868. /**
  869. * Checks to see if a player can build at a location. This will return
  870. * true if region protection is disabled.
  871. *
  872. * @param player The player to check.
  873. * @param loc The location to check at.
  874. * @see GlobalRegionManager#canBuild(org.bukkit.entity.Player, org.bukkit.Location)
  875. * @return whether {@code player} can build at {@code loc}
  876. */
  877. public boolean canBuild(Player player, Location loc) {
  878. return getGlobalRegionManager().canBuild(player, loc);
  879. }
  880. /**
  881. * Checks to see if a player can build at a location. This will return
  882. * true if region protection is disabled.
  883. *
  884. * @param player The player to check
  885. * @param block The block to check at.
  886. * @see GlobalRegionManager#canBuild(org.bukkit.entity.Player, org.bukkit.block.Block)
  887. * @return whether {@code player} can build at {@code block}'s location
  888. */
  889. public boolean canBuild(Player player, Block block) {
  890. return getGlobalRegionManager().canBuild(player, block);
  891. }
  892. /**
  893. * Gets the region manager for a world.
  894. *
  895. * @param world world to get the region manager for
  896. * @return the region manager or null if regions are not enabled
  897. */
  898. public RegionManager getRegionManager(World world) {
  899. if (!getGlobalStateManager().get(world).useRegions) {
  900. return null;
  901. }
  902. return getGlobalRegionManager().get(world);
  903. }
  904. public PlayerMoveListener getPlayerMoveListener() {
  905. return playerMoveListener;
  906. }
  907. /**
  908. * Replace macros in the text.
  909. *
  910. * The macros replaced are as follows:
  911. * %name%: The name of {@code sender}. See {@link #toName(org.bukkit.command.CommandSender)}
  912. * %id%: The unique name of the sender. See {@link #toUniqueName(org.bukkit.command.CommandSender)}
  913. * %online%: The number of players currently online on the server
  914. * If {@code sender} is a Player:
  915. * %world%: The name of the world {@code sender} is located in
  916. * %health%: The health of {@code sender}. See {@link org.bukkit.entity.Player#getHealth()}
  917. *
  918. * @param sender The sender to check
  919. * @param message The message to replace macros in
  920. * @return The message with macros replaced
  921. */
  922. public String replaceMacros(CommandSender sender, String message) {
  923. Collection<? extends Player> online = BukkitUtil.getOnlinePlayers();
  924. message = message.replace("%name%", toName(sender));
  925. message = message.replace("%id%", toUniqueName(sender));
  926. message = message.replace("%online%", String.valueOf(online.size()));
  927. if (sender instanceof Player) {
  928. Player player = (Player) sender;
  929. World world = player.getWorld();
  930. message = message.replace("%world%", world.getName());
  931. message = message.replace("%health%", String.valueOf(player.getHealth()));
  932. }
  933. return message;
  934. }
  935. }