Commits
Wesley Wolfe authored b602b5efa44
116 116 | import org.bukkit.command.CommandException; |
117 117 | import org.bukkit.command.CommandSender; |
118 118 | import org.bukkit.command.ConsoleCommandSender; |
119 119 | import org.bukkit.command.PluginCommand; |
120 120 | import org.bukkit.command.SimpleCommandMap; |
121 121 | import org.bukkit.configuration.ConfigurationSection; |
122 122 | import org.bukkit.configuration.file.YamlConfiguration; |
123 123 | import org.bukkit.configuration.serialization.ConfigurationSerialization; |
124 124 | import org.bukkit.conversations.Conversable; |
125 125 | import org.bukkit.craftbukkit.command.VanillaCommandWrapper; |
126 + | import org.bukkit.craftbukkit.entity.CraftPlayer; |
126 127 | import org.bukkit.craftbukkit.help.SimpleHelpMap; |
127 128 | import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe; |
128 129 | import org.bukkit.craftbukkit.inventory.CraftInventoryCustom; |
129 130 | import org.bukkit.craftbukkit.inventory.CraftItemFactory; |
130 131 | import org.bukkit.craftbukkit.inventory.CraftRecipe; |
131 132 | import org.bukkit.craftbukkit.inventory.CraftShapedRecipe; |
132 133 | import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe; |
133 134 | import org.bukkit.craftbukkit.inventory.RecipeIterator; |
134 135 | import org.bukkit.craftbukkit.map.CraftMapView; |
135 136 | import org.bukkit.craftbukkit.metadata.EntityMetadataStore; |
178 179 | import org.bukkit.util.permissions.DefaultPermissions; |
179 180 | import org.yaml.snakeyaml.Yaml; |
180 181 | import org.yaml.snakeyaml.constructor.SafeConstructor; |
181 182 | import org.yaml.snakeyaml.error.MarkedYAMLException; |
182 183 | import org.apache.commons.lang.Validate; |
183 184 | |
184 185 | import com.avaje.ebean.config.DataSourceConfig; |
185 186 | import com.avaje.ebean.config.ServerConfig; |
186 187 | import com.avaje.ebean.config.dbplatform.SQLitePlatform; |
187 188 | import com.avaje.ebeaninternal.server.lib.sql.TransactionIsolation; |
189 + | import com.google.common.base.Function; |
188 190 | import com.google.common.collect.ImmutableList; |
191 + | import com.google.common.collect.Lists; |
189 192 | import com.google.common.collect.MapMaker; |
190 193 | |
191 194 | import jline.console.ConsoleReader; |
192 195 | |
193 196 | public final class CraftServer implements Server { |
197 + | private static final Player[] EMPTY_PLAYER_ARRAY = new Player[0]; |
194 198 | private final String serverName = "CraftBukkit"; |
195 199 | private final String serverVersion; |
196 200 | private final String bukkitVersion = Versioning.getBukkitVersion(); |
197 201 | private final Logger logger = Logger.getLogger("Minecraft"); |
198 202 | private final ServicesManager servicesManager = new SimpleServicesManager(); |
199 203 | private final CraftScheduler scheduler = new CraftScheduler(); |
200 204 | private final SimpleCommandMap commandMap = new SimpleCommandMap(this); |
201 205 | private final SimpleHelpMap helpMap = new SimpleHelpMap(this); |
202 206 | private final StandardMessenger messenger = new StandardMessenger(); |
203 207 | private final PluginManager pluginManager = new SimplePluginManager(this, commandMap); |
221 225 | private File container; |
222 226 | private WarningState warningState = WarningState.DEFAULT; |
223 227 | private final BooleanWrapper online = new BooleanWrapper(); |
224 228 | public CraftScoreboardManager scoreboardManager; |
225 229 | public boolean playerCommandState; |
226 230 | private boolean printSaveWarning; |
227 231 | private CraftIconCache icon; |
228 232 | private boolean overrideAllCommandBlockCommands = false; |
229 233 | private final Pattern validUserPattern = Pattern.compile("^[a-zA-Z0-9_]{2,16}$"); |
230 234 | private final UUID invalidUserUUID = UUID.nameUUIDFromBytes("InvalidUsername".getBytes(Charsets.UTF_8)); |
235 + | private final List<CraftPlayer> playerView; |
231 236 | |
232 237 | private final class BooleanWrapper { |
233 238 | private boolean value = true; |
234 239 | } |
235 240 | |
236 241 | static { |
237 242 | ConfigurationSerialization.registerClass(CraftOfflinePlayer.class); |
238 243 | CraftItemFactory.instance(); |
239 244 | } |
240 245 | |
241 246 | public CraftServer(MinecraftServer console, PlayerList playerList) { |
242 247 | this.console = console; |
243 248 | this.playerList = (DedicatedPlayerList) playerList; |
249 + | this.playerView = Collections.unmodifiableList(Lists.transform(playerList.players, new Function<EntityPlayer, CraftPlayer>() { |
250 + | |
251 + | public CraftPlayer apply(EntityPlayer player) { |
252 + | return player.getBukkitEntity(); |
253 + | } |
254 + | })); |
244 255 | this.serverVersion = CraftServer.class.getPackage().getImplementationVersion(); |
245 256 | online.value = console.getPropertyManager().getBoolean("online-mode", true); |
246 257 | |
247 258 | Bukkit.setServer(this); |
248 259 | |
249 260 | // Register all the Enchantments and PotionTypes now so we can stop new registration immediately after |
250 261 | Enchantment.DAMAGE_ALL.getClass(); |
251 262 | org.bukkit.enchantments.Enchantment.stopAcceptingRegistrations(); |
252 263 | |
253 264 | Potion.setPotionBrewer(new CraftPotionBrewer()); |
452 463 | pluginManager.addPermission(perm); |
453 464 | } catch (IllegalArgumentException ex) { |
454 465 | getLogger().log(Level.WARNING, "Plugin " + plugin.getDescription().getFullName() + " tried to register permission '" + perm.getName() + "' but it's already registered", ex); |
455 466 | } |
456 467 | } |
457 468 | } catch (Throwable ex) { |
458 469 | Logger.getLogger(CraftServer.class.getName()).log(Level.SEVERE, ex.getMessage() + " loading " + plugin.getDescription().getFullName() + " (Is it up to date?)", ex); |
459 470 | } |
460 471 | } |
461 472 | |
473 + | |
462 474 | public String getName() { |
463 475 | return serverName; |
464 476 | } |
465 477 | |
478 + | |
466 479 | public String getVersion() { |
467 480 | return serverVersion + " (MC: " + console.getVersion() + ")"; |
468 481 | } |
469 482 | |
483 + | |
470 484 | public String getBukkitVersion() { |
471 485 | return bukkitVersion; |
472 486 | } |
473 487 | |
488 + | |
489 + | |
474 490 | "unchecked") | (
475 - | public Player[] getOnlinePlayers() { |
476 - | List<EntityPlayer> online = playerList.players; |
477 - | Player[] players = new Player[online.size()]; |
478 - | |
479 - | for (int i = 0; i < players.length; i++) { |
480 - | players[i] = online.get(i).playerConnection.getPlayer(); |
481 - | } |
491 + | public Player[] _INVALID_getOnlinePlayers() { |
492 + | return getOnlinePlayers().toArray(EMPTY_PLAYER_ARRAY); |
493 + | } |
482 494 | |
483 - | return players; |
495 + | |
496 + | public List<CraftPlayer> getOnlinePlayers() { |
497 + | return this.playerView; |
484 498 | } |
485 499 | |
500 + | |
501 + | |
486 502 | public Player getPlayer(final String name) { |
487 503 | Validate.notNull(name, "Name cannot be null"); |
488 504 | |
489 - | Player[] players = getOnlinePlayers(); |
490 - | |
491 505 | Player found = null; |
492 506 | String lowerName = name.toLowerCase(); |
493 507 | int delta = Integer.MAX_VALUE; |
494 - | for (Player player : players) { |
508 + | for (Player player : getOnlinePlayers()) { |
495 509 | if (player.getName().toLowerCase().startsWith(lowerName)) { |
496 510 | int curDelta = player.getName().length() - lowerName.length(); |
497 511 | if (curDelta < delta) { |
498 512 | found = player; |
499 513 | delta = curDelta; |
500 514 | } |
501 515 | if (curDelta == 0) break; |
502 516 | } |
503 517 | } |
504 518 | return found; |
505 519 | } |
506 520 | |
521 + | |
522 + | |
507 523 | public Player getPlayerExact(String name) { |
508 524 | Validate.notNull(name, "Name cannot be null"); |
509 525 | |
510 526 | String lname = name.toLowerCase(); |
511 527 | |
512 528 | for (Player player : getOnlinePlayers()) { |
513 529 | if (player.getName().equalsIgnoreCase(lname)) { |
514 530 | return player; |
515 531 | } |
516 532 | } |
517 533 | |
518 534 | return null; |
519 535 | } |
520 536 | |
521 537 | // TODO: In 1.8+ this should use the server's UUID->EntityPlayer map |
538 + | |
522 539 | public Player getPlayer(UUID id) { |
523 540 | for (Player player : getOnlinePlayers()) { |
524 541 | if (player.getUniqueId().equals(id)) { |
525 542 | return player; |
526 543 | } |
527 544 | } |
528 545 | |
529 546 | return null; |
530 547 | } |
531 548 | |
549 + | |
532 550 | public int broadcastMessage(String message) { |
533 551 | return broadcast(message, BROADCAST_CHANNEL_USERS); |
534 552 | } |
535 553 | |
536 554 | public Player getPlayer(final EntityPlayer entity) { |
537 555 | return entity.playerConnection.getPlayer(); |
538 556 | } |
539 557 | |
558 + | |
559 + | |
540 560 | public List<Player> matchPlayer(String partialName) { |
541 561 | Validate.notNull(partialName, "PartialName cannot be null"); |
542 562 | |
543 563 | List<Player> matchedPlayers = new ArrayList<Player>(); |
544 564 | |
545 565 | for (Player iterPlayer : this.getOnlinePlayers()) { |
546 566 | String iterPlayerName = iterPlayer.getName(); |
547 567 | |
548 568 | if (partialName.equalsIgnoreCase(iterPlayerName)) { |
549 569 | // Exact match |
553 573 | } |
554 574 | if (iterPlayerName.toLowerCase().contains(partialName.toLowerCase())) { |
555 575 | // Partial match |
556 576 | matchedPlayers.add(iterPlayer); |
557 577 | } |
558 578 | } |
559 579 | |
560 580 | return matchedPlayers; |
561 581 | } |
562 582 | |
583 + | |
563 584 | public int getMaxPlayers() { |
564 585 | return playerList.getMaxPlayers(); |
565 586 | } |
566 587 | |
567 588 | // NOTE: These are dependent on the corrisponding call in MinecraftServer |
568 589 | // so if that changes this will need to as well |
590 + | |
569 591 | public int getPort() { |
570 592 | return this.getConfigInt("server-port", 25565); |
571 593 | } |
572 594 | |
595 + | |
573 596 | public int getViewDistance() { |
574 597 | return this.getConfigInt("view-distance", 10); |
575 598 | } |
576 599 | |
600 + | |
577 601 | public String getIp() { |
578 602 | return this.getConfigString("server-ip", ""); |
579 603 | } |
580 604 | |
605 + | |
581 606 | public String getServerName() { |
582 607 | return this.getConfigString("server-name", "Unknown Server"); |
583 608 | } |
584 609 | |
610 + | |
585 611 | public String getServerId() { |
586 612 | return this.getConfigString("server-id", "unnamed"); |
587 613 | } |
588 614 | |
615 + | |
589 616 | public String getWorldType() { |
590 617 | return this.getConfigString("level-type", "DEFAULT"); |
591 618 | } |
592 619 | |
620 + | |
593 621 | public boolean getGenerateStructures() { |
594 622 | return this.getConfigBoolean("generate-structures", true); |
595 623 | } |
596 624 | |
625 + | |
597 626 | public boolean getAllowEnd() { |
598 627 | return this.configuration.getBoolean("settings.allow-end"); |
599 628 | } |
600 629 | |
630 + | |
601 631 | public boolean getAllowNether() { |
602 632 | return this.getConfigBoolean("allow-nether", true); |
603 633 | } |
604 634 | |
605 635 | public boolean getWarnOnOverload() { |
606 636 | return this.configuration.getBoolean("settings.warn-on-overload"); |
607 637 | } |
608 638 | |
609 639 | public boolean getQueryPlugins() { |
610 640 | return this.configuration.getBoolean("settings.query-plugins"); |
611 641 | } |
612 642 | |
643 + | |
613 644 | public boolean hasWhitelist() { |
614 645 | return this.getConfigBoolean("white-list", false); |
615 646 | } |
616 647 | |
617 648 | // NOTE: Temporary calls through to server.properies until its replaced |
618 649 | private String getConfigString(String variable, String defaultValue) { |
619 650 | return this.console.getPropertyManager().getString(variable, defaultValue); |
620 651 | } |
621 652 | |
622 653 | private int getConfigInt(String variable, int defaultValue) { |
623 654 | return this.console.getPropertyManager().getInt(variable, defaultValue); |
624 655 | } |
625 656 | |
626 657 | private boolean getConfigBoolean(String variable, boolean defaultValue) { |
627 658 | return this.console.getPropertyManager().getBoolean(variable, defaultValue); |
628 659 | } |
629 660 | |
630 661 | // End Temporary calls |
631 662 | |
663 + | |
632 664 | public String getUpdateFolder() { |
633 665 | return this.configuration.getString("settings.update-folder", "update"); |
634 666 | } |
635 667 | |
668 + | |
636 669 | public File getUpdateFolderFile() { |
637 670 | return new File((File) console.options.valueOf("plugins"), this.configuration.getString("settings.update-folder", "update")); |
638 671 | } |
639 672 | |
640 673 | public int getPingPacketLimit() { |
641 674 | return this.configuration.getInt("settings.ping-packet-limit", 100); |
642 675 | } |
643 676 | |
677 + | |
644 678 | public long getConnectionThrottle() { |
645 679 | return this.configuration.getInt("settings.connection-throttle"); |
646 680 | } |
647 681 | |
682 + | |
648 683 | public int getTicksPerAnimalSpawns() { |
649 684 | return this.configuration.getInt("ticks-per.animal-spawns"); |
650 685 | } |
651 686 | |
687 + | |
652 688 | public int getTicksPerMonsterSpawns() { |
653 689 | return this.configuration.getInt("ticks-per.monster-spawns"); |
654 690 | } |
655 691 | |
692 + | |
656 693 | public PluginManager getPluginManager() { |
657 694 | return pluginManager; |
658 695 | } |
659 696 | |
697 + | |
660 698 | public CraftScheduler getScheduler() { |
661 699 | return scheduler; |
662 700 | } |
663 701 | |
702 + | |
664 703 | public ServicesManager getServicesManager() { |
665 704 | return servicesManager; |
666 705 | } |
667 706 | |
707 + | |
668 708 | public List<World> getWorlds() { |
669 709 | return new ArrayList<World>(worlds.values()); |
670 710 | } |
671 711 | |
672 712 | public DedicatedPlayerList getHandle() { |
673 713 | return playerList; |
674 714 | } |
675 715 | |
676 716 | // NOTE: Should only be called from DedicatedServer.ah() |
677 717 | public boolean dispatchServerCommand(CommandSender sender, ServerCommand serverCommand) { |
687 727 | this.playerCommandState = true; |
688 728 | return dispatchCommand(sender, serverCommand.command); |
689 729 | } catch (Exception ex) { |
690 730 | getLogger().log(Level.WARNING, "Unexpected exception while parsing console command \"" + serverCommand.command + '"', ex); |
691 731 | return false; |
692 732 | } finally { |
693 733 | this.playerCommandState = false; |
694 734 | } |
695 735 | } |
696 736 | |
737 + | |
697 738 | public boolean dispatchCommand(CommandSender sender, String commandLine) { |
698 739 | Validate.notNull(sender, "Sender cannot be null"); |
699 740 | Validate.notNull(commandLine, "CommandLine cannot be null"); |
700 741 | |
701 742 | if (commandMap.dispatch(sender, commandLine)) { |
702 743 | return true; |
703 744 | } |
704 745 | |
705 746 | if (sender instanceof Player) { |
706 747 | sender.sendMessage("Unknown command. Type \"/help\" for help."); |
707 748 | } else { |
708 749 | sender.sendMessage("Unknown command. Type \"help\" for help."); |
709 750 | } |
710 751 | |
711 752 | return false; |
712 753 | } |
713 754 | |
755 + | |
714 756 | public void reload() { |
715 757 | configuration = YamlConfiguration.loadConfiguration(getConfigFile()); |
716 758 | commandsConfiguration = YamlConfiguration.loadConfiguration(getCommandsConfigFile()); |
717 759 | PropertyManager config = new PropertyManager(console.options); |
718 760 | |
719 761 | ((DedicatedServer) console).propertyManager = config; |
720 762 | |
721 763 | boolean animals = config.getBoolean("spawn-animals", console.getSpawnAnimals()); |
722 764 | boolean monsters = config.getBoolean("spawn-monsters", console.worlds.get(0).difficulty != EnumDifficulty.PEACEFUL); |
723 765 | EnumDifficulty difficulty = EnumDifficulty.a(config.getInt("difficulty", console.worlds.get(0).difficulty.ordinal())); |
872 914 | } |
873 915 | |
874 916 | public World createWorld(String name, Environment environment, ChunkGenerator generator) { |
875 917 | return WorldCreator.name(name).environment(environment).generator(generator).createWorld(); |
876 918 | } |
877 919 | |
878 920 | public World createWorld(String name, Environment environment, long seed, ChunkGenerator generator) { |
879 921 | return WorldCreator.name(name).environment(environment).seed(seed).generator(generator).createWorld(); |
880 922 | } |
881 923 | |
924 + | |
882 925 | public World createWorld(WorldCreator creator) { |
883 926 | Validate.notNull(creator, "Creator may not be null"); |
884 927 | |
885 928 | String name = creator.name(); |
886 929 | ChunkGenerator generator = creator.generator(); |
887 930 | File folder = new File(getWorldContainer(), name); |
888 931 | World world = getWorld(name); |
889 932 | WorldType type = WorldType.getType(creator.type().getName()); |
890 933 | boolean generateStructures = creator.generateStructures(); |
891 934 | |
962 1005 | |
963 1006 | ChunkCoordinates chunkcoordinates = internal.getSpawn(); |
964 1007 | internal.chunkProviderServer.getChunkAt(chunkcoordinates.x + j >> 4, chunkcoordinates.z + k >> 4); |
965 1008 | } |
966 1009 | } |
967 1010 | } |
968 1011 | pluginManager.callEvent(new WorldLoadEvent(internal.getWorld())); |
969 1012 | return internal.getWorld(); |
970 1013 | } |
971 1014 | |
1015 + | |
972 1016 | public boolean unloadWorld(String name, boolean save) { |
973 1017 | return unloadWorld(getWorld(name), save); |
974 1018 | } |
975 1019 | |
1020 + | |
976 1021 | public boolean unloadWorld(World world, boolean save) { |
977 1022 | if (world == null) { |
978 1023 | return false; |
979 1024 | } |
980 1025 | |
981 1026 | WorldServer handle = ((CraftWorld) world).getHandle(); |
982 1027 | |
983 1028 | if (!(console.worlds.contains(handle))) { |
984 1029 | return false; |
985 1030 | } |
1013 1058 | worlds.remove(world.getName().toLowerCase()); |
1014 1059 | console.worlds.remove(console.worlds.indexOf(handle)); |
1015 1060 | |
1016 1061 | return true; |
1017 1062 | } |
1018 1063 | |
1019 1064 | public MinecraftServer getServer() { |
1020 1065 | return console; |
1021 1066 | } |
1022 1067 | |
1068 + | |
1023 1069 | public World getWorld(String name) { |
1024 1070 | Validate.notNull(name, "Name cannot be null"); |
1025 1071 | |
1026 1072 | return worlds.get(name.toLowerCase()); |
1027 1073 | } |
1028 1074 | |
1075 + | |
1029 1076 | public World getWorld(UUID uid) { |
1030 1077 | for (World world : worlds.values()) { |
1031 1078 | if (world.getUID().equals(uid)) { |
1032 1079 | return world; |
1033 1080 | } |
1034 1081 | } |
1035 1082 | return null; |
1036 1083 | } |
1037 1084 | |
1038 1085 | public void addWorld(World world) { |
1039 1086 | // Check if a World already exists with the UID. |
1040 1087 | if (getWorld(world.getUID()) != null) { |
1041 1088 | System.out.println("World " + world.getName() + " is a duplicate of another world and has been prevented from loading. Please delete the uid.dat file from " + world.getName() + "'s world directory if you want to be able to load the duplicate world."); |
1042 1089 | return; |
1043 1090 | } |
1044 1091 | worlds.put(world.getName().toLowerCase(), world); |
1045 1092 | } |
1046 1093 | |
1094 + | |
1047 1095 | public Logger getLogger() { |
1048 1096 | return logger; |
1049 1097 | } |
1050 1098 | |
1051 1099 | public ConsoleReader getReader() { |
1052 1100 | return console.reader; |
1053 1101 | } |
1054 1102 | |
1103 + | |
1055 1104 | public PluginCommand getPluginCommand(String name) { |
1056 1105 | Command command = commandMap.getCommand(name); |
1057 1106 | |
1058 1107 | if (command instanceof PluginCommand) { |
1059 1108 | return (PluginCommand) command; |
1060 1109 | } else { |
1061 1110 | return null; |
1062 1111 | } |
1063 1112 | } |
1064 1113 | |
1114 + | |
1065 1115 | public void savePlayers() { |
1066 1116 | checkSaveState(); |
1067 1117 | playerList.savePlayers(); |
1068 1118 | } |
1069 1119 | |
1120 + | |
1070 1121 | public void configureDbConfig(ServerConfig config) { |
1071 1122 | Validate.notNull(config, "Config cannot be null"); |
1072 1123 | |
1073 1124 | DataSourceConfig ds = new DataSourceConfig(); |
1074 1125 | ds.setDriver(configuration.getString("database.driver")); |
1075 1126 | ds.setUrl(configuration.getString("database.url")); |
1076 1127 | ds.setUsername(configuration.getString("database.username")); |
1077 1128 | ds.setPassword(configuration.getString("database.password")); |
1078 1129 | ds.setIsolationLevel(TransactionIsolation.getLevel(configuration.getString("database.isolation"))); |
1079 1130 | |
1080 1131 | if (ds.getDriver().contains("sqlite")) { |
1081 1132 | config.setDatabasePlatform(new SQLitePlatform()); |
1082 1133 | config.getDatabasePlatform().getDbDdlSyntax().setIdentity(""); |
1083 1134 | } |
1084 1135 | |
1085 1136 | config.setDataSourceConfig(ds); |
1086 1137 | } |
1087 1138 | |
1139 + | |
1088 1140 | public boolean addRecipe(Recipe recipe) { |
1089 1141 | CraftRecipe toAdd; |
1090 1142 | if (recipe instanceof CraftRecipe) { |
1091 1143 | toAdd = (CraftRecipe) recipe; |
1092 1144 | } else { |
1093 1145 | if (recipe instanceof ShapedRecipe) { |
1094 1146 | toAdd = CraftShapedRecipe.fromBukkitRecipe((ShapedRecipe) recipe); |
1095 1147 | } else if (recipe instanceof ShapelessRecipe) { |
1096 1148 | toAdd = CraftShapelessRecipe.fromBukkitRecipe((ShapelessRecipe) recipe); |
1097 1149 | } else if (recipe instanceof FurnaceRecipe) { |
1098 1150 | toAdd = CraftFurnaceRecipe.fromBukkitRecipe((FurnaceRecipe) recipe); |
1099 1151 | } else { |
1100 1152 | return false; |
1101 1153 | } |
1102 1154 | } |
1103 1155 | toAdd.addToCraftingManager(); |
1104 1156 | CraftingManager.getInstance().sort(); |
1105 1157 | return true; |
1106 1158 | } |
1107 1159 | |
1160 + | |
1108 1161 | public List<Recipe> getRecipesFor(ItemStack result) { |
1109 1162 | Validate.notNull(result, "Result cannot be null"); |
1110 1163 | |
1111 1164 | List<Recipe> results = new ArrayList<Recipe>(); |
1112 1165 | Iterator<Recipe> iter = recipeIterator(); |
1113 1166 | while (iter.hasNext()) { |
1114 1167 | Recipe recipe = iter.next(); |
1115 1168 | ItemStack stack = recipe.getResult(); |
1116 1169 | if (stack.getType() != result.getType()) { |
1117 1170 | continue; |
1118 1171 | } |
1119 1172 | if (result.getDurability() == -1 || result.getDurability() == stack.getDurability()) { |
1120 1173 | results.add(recipe); |
1121 1174 | } |
1122 1175 | } |
1123 1176 | return results; |
1124 1177 | } |
1125 1178 | |
1179 + | |
1126 1180 | public Iterator<Recipe> recipeIterator() { |
1127 1181 | return new RecipeIterator(); |
1128 1182 | } |
1129 1183 | |
1184 + | |
1130 1185 | public void clearRecipes() { |
1131 1186 | CraftingManager.getInstance().recipes.clear(); |
1132 1187 | RecipesFurnace.getInstance().recipes.clear(); |
1133 1188 | RecipesFurnace.getInstance().customRecipes.clear(); |
1134 1189 | } |
1135 1190 | |
1191 + | |
1136 1192 | public void resetRecipes() { |
1137 1193 | CraftingManager.getInstance().recipes = new CraftingManager().recipes; |
1138 1194 | RecipesFurnace.getInstance().recipes = new RecipesFurnace().recipes; |
1139 1195 | RecipesFurnace.getInstance().customRecipes.clear(); |
1140 1196 | } |
1141 1197 | |
1198 + | |
1142 1199 | public Map<String, String[]> getCommandAliases() { |
1143 1200 | ConfigurationSection section = commandsConfiguration.getConfigurationSection("aliases"); |
1144 1201 | Map<String, String[]> result = new LinkedHashMap<String, String[]>(); |
1145 1202 | |
1146 1203 | if (section != null) { |
1147 1204 | for (String key : section.getKeys(false)) { |
1148 1205 | List<String> commands; |
1149 1206 | |
1150 1207 | if (section.isList(key)) { |
1151 1208 | commands = section.getStringList(key); |
1162 1219 | |
1163 1220 | public void removeBukkitSpawnRadius() { |
1164 1221 | configuration.set("settings.spawn-radius", null); |
1165 1222 | saveConfig(); |
1166 1223 | } |
1167 1224 | |
1168 1225 | public int getBukkitSpawnRadius() { |
1169 1226 | return configuration.getInt("settings.spawn-radius", -1); |
1170 1227 | } |
1171 1228 | |
1229 + | |
1172 1230 | public String getShutdownMessage() { |
1173 1231 | return configuration.getString("settings.shutdown-message"); |
1174 1232 | } |
1175 1233 | |
1234 + | |
1176 1235 | public int getSpawnRadius() { |
1177 1236 | return ((DedicatedServer) console).propertyManager.getInt("spawn-protection", 16); |
1178 1237 | } |
1179 1238 | |
1239 + | |
1180 1240 | public void setSpawnRadius(int value) { |
1181 1241 | configuration.set("settings.spawn-radius", value); |
1182 1242 | saveConfig(); |
1183 1243 | } |
1184 1244 | |
1245 + | |
1185 1246 | public boolean getOnlineMode() { |
1186 1247 | return online.value; |
1187 1248 | } |
1188 1249 | |
1250 + | |
1189 1251 | public boolean getAllowFlight() { |
1190 1252 | return console.getAllowFlight(); |
1191 1253 | } |
1192 1254 | |
1255 + | |
1193 1256 | public boolean isHardcore() { |
1194 1257 | return console.isHardcore(); |
1195 1258 | } |
1196 1259 | |
1260 + | |
1197 1261 | public boolean useExactLoginLocation() { |
1198 1262 | return configuration.getBoolean("settings.use-exact-login-location"); |
1199 1263 | } |
1200 1264 | |
1201 1265 | public ChunkGenerator getGenerator(String world) { |
1202 1266 | ConfigurationSection section = configuration.getConfigurationSection("worlds"); |
1203 1267 | ChunkGenerator result = null; |
1204 1268 | |
1205 1269 | if (section != null) { |
1206 1270 | section = section.getConfigurationSection(world); |
1227 1291 | plugin.getLogger().log(Level.SEVERE, "Could not set generator for default world '" + world + "': Plugin '" + plugin.getDescription().getFullName(), t); |
1228 1292 | } |
1229 1293 | } |
1230 1294 | } |
1231 1295 | } |
1232 1296 | } |
1233 1297 | |
1234 1298 | return result; |
1235 1299 | } |
1236 1300 | |
1301 + | |
1302 + | |
1237 1303 | public CraftMapView getMap(short id) { |
1238 1304 | PersistentCollection collection = console.worlds.get(0).worldMaps; |
1239 1305 | WorldMap worldmap = (WorldMap) collection.get(WorldMap.class, "map_" + id); |
1240 1306 | if (worldmap == null) { |
1241 1307 | return null; |
1242 1308 | } |
1243 1309 | return worldmap.mapView; |
1244 1310 | } |
1245 1311 | |
1312 + | |
1246 1313 | public CraftMapView createMap(World world) { |
1247 1314 | Validate.notNull(world, "World cannot be null"); |
1248 1315 | |
1249 1316 | net.minecraft.server.ItemStack stack = new net.minecraft.server.ItemStack(Items.MAP, 1, -1); |
1250 1317 | WorldMap worldmap = Items.MAP.getSavedMap(stack, ((CraftWorld) world).getHandle()); |
1251 1318 | return worldmap.mapView; |
1252 1319 | } |
1253 1320 | |
1321 + | |
1254 1322 | public void shutdown() { |
1255 1323 | console.safeShutdown(); |
1256 1324 | } |
1257 1325 | |
1326 + | |
1258 1327 | public int broadcast(String message, String permission) { |
1259 1328 | int count = 0; |
1260 1329 | Set<Permissible> permissibles = getPluginManager().getPermissionSubscriptions(permission); |
1261 1330 | |
1262 1331 | for (Permissible permissible : permissibles) { |
1263 1332 | if (permissible instanceof CommandSender && permissible.hasPermission(permission)) { |
1264 1333 | CommandSender user = (CommandSender) permissible; |
1265 1334 | user.sendMessage(message); |
1266 1335 | count++; |
1267 1336 | } |
1268 1337 | } |
1269 1338 | |
1270 1339 | return count; |
1271 1340 | } |
1272 1341 | |
1342 + | |
1343 + | |
1273 1344 | public OfflinePlayer getOfflinePlayer(String name) { |
1274 1345 | Validate.notNull(name, "Name cannot be null"); |
1275 1346 | |
1276 1347 | // If the name given cannot ever be a valid username give a dummy return, for scoreboard plugins |
1277 1348 | if (!validUserPattern.matcher(name).matches()) { |
1278 1349 | return new CraftOfflinePlayer(this, new GameProfile(invalidUserUUID, name)); |
1279 1350 | } |
1280 1351 | |
1281 1352 | OfflinePlayer result = getPlayerExact(name); |
1282 1353 | if (result == null) { |
1289 1360 | // Use the GameProfile even when we get a UUID so we ensure we still have a name |
1290 1361 | result = getOfflinePlayer(profile); |
1291 1362 | } |
1292 1363 | } else { |
1293 1364 | offlinePlayers.remove(result.getUniqueId()); |
1294 1365 | } |
1295 1366 | |
1296 1367 | return result; |
1297 1368 | } |
1298 1369 | |
1370 + | |
1299 1371 | public OfflinePlayer getOfflinePlayer(UUID id) { |
1300 1372 | Validate.notNull(id, "UUID cannot be null"); |
1301 1373 | |
1302 1374 | OfflinePlayer result = getPlayer(id); |
1303 1375 | if (result == null) { |
1304 1376 | result = offlinePlayers.get(id); |
1305 1377 | if (result == null) { |
1306 1378 | result = new CraftOfflinePlayer(this, new GameProfile(id, null)); |
1307 1379 | offlinePlayers.put(id, result); |
1308 1380 | } |
1312 1384 | |
1313 1385 | return result; |
1314 1386 | } |
1315 1387 | |
1316 1388 | public OfflinePlayer getOfflinePlayer(GameProfile profile) { |
1317 1389 | OfflinePlayer player = new CraftOfflinePlayer(this, profile); |
1318 1390 | offlinePlayers.put(profile.getId(), player); |
1319 1391 | return player; |
1320 1392 | } |
1321 1393 | |
1394 + | |
1322 1395 | "unchecked") | (
1323 1396 | public Set<String> getIPBans() { |
1324 1397 | return new HashSet<String>(Arrays.asList(playerList.getIPBans().getEntries())); |
1325 1398 | } |
1326 1399 | |
1400 + | |
1327 1401 | public void banIP(String address) { |
1328 1402 | Validate.notNull(address, "Address cannot be null."); |
1329 1403 | |
1330 1404 | this.getBanList(org.bukkit.BanList.Type.IP).addBan(address, null, null, null); |
1331 1405 | } |
1332 1406 | |
1407 + | |
1333 1408 | public void unbanIP(String address) { |
1334 1409 | Validate.notNull(address, "Address cannot be null."); |
1335 1410 | |
1336 1411 | this.getBanList(org.bukkit.BanList.Type.IP).pardon(address); |
1337 1412 | } |
1338 1413 | |
1414 + | |
1339 1415 | public Set<OfflinePlayer> getBannedPlayers() { |
1340 1416 | Set<OfflinePlayer> result = new HashSet<OfflinePlayer>(); |
1341 1417 | |
1342 1418 | for (JsonListEntry entry : playerList.getProfileBans().getValues()) { |
1343 1419 | result.add(getOfflinePlayer((GameProfile) entry.f())); // Should be getKey |
1344 1420 | } |
1345 1421 | |
1346 1422 | return result; |
1347 1423 | } |
1348 1424 | |
1352 1428 | |
1353 1429 | switch(type){ |
1354 1430 | case IP: |
1355 1431 | return new CraftIpBanList(playerList.getIPBans()); |
1356 1432 | case NAME: |
1357 1433 | default: |
1358 1434 | return new CraftProfileBanList(playerList.getProfileBans()); |
1359 1435 | } |
1360 1436 | } |
1361 1437 | |
1438 + | |
1362 1439 | public void setWhitelist(boolean value) { |
1363 1440 | playerList.setHasWhitelist(value); |
1364 1441 | console.getPropertyManager().a("white-list", value); |
1365 1442 | } |
1366 1443 | |
1444 + | |
1367 1445 | public Set<OfflinePlayer> getWhitelistedPlayers() { |
1368 1446 | Set<OfflinePlayer> result = new LinkedHashSet<OfflinePlayer>(); |
1369 1447 | |
1370 1448 | for (JsonListEntry entry : playerList.getWhitelist().getValues()) { |
1371 1449 | result.add(getOfflinePlayer((GameProfile) entry.f())); // Should be getKey |
1372 1450 | } |
1373 1451 | |
1374 1452 | return result; |
1375 1453 | } |
1376 1454 | |
1455 + | |
1377 1456 | public Set<OfflinePlayer> getOperators() { |
1378 1457 | Set<OfflinePlayer> result = new HashSet<OfflinePlayer>(); |
1379 1458 | |
1380 1459 | for (JsonListEntry entry : playerList.getOPs().getValues()) { |
1381 1460 | result.add(getOfflinePlayer((GameProfile) entry.f())); // Should be getKey |
1382 1461 | } |
1383 1462 | |
1384 1463 | return result; |
1385 1464 | } |
1386 1465 | |
1466 + | |
1387 1467 | public void reloadWhitelist() { |
1388 1468 | playerList.reloadWhitelist(); |
1389 1469 | } |
1390 1470 | |
1471 + | |
1391 1472 | public GameMode getDefaultGameMode() { |
1392 1473 | return GameMode.getByValue(console.worlds.get(0).getWorldData().getGameType().a()); |
1393 1474 | } |
1394 1475 | |
1476 + | |
1395 1477 | public void setDefaultGameMode(GameMode mode) { |
1396 1478 | Validate.notNull(mode, "Mode cannot be null"); |
1397 1479 | |
1398 1480 | for (World world : getWorlds()) { |
1399 1481 | ((CraftWorld) world).getHandle().worldData.setGameType(EnumGamemode.a(mode.getValue())); |
1400 1482 | } |
1401 1483 | } |
1402 1484 | |
1485 + | |
1403 1486 | public ConsoleCommandSender getConsoleSender() { |
1404 1487 | return console.console; |
1405 1488 | } |
1406 1489 | |
1407 1490 | public EntityMetadataStore getEntityMetadata() { |
1408 1491 | return entityMetadata; |
1409 1492 | } |
1410 1493 | |
1411 1494 | public PlayerMetadataStore getPlayerMetadata() { |
1412 1495 | return playerMetadata; |
1430 1513 | entityPlayer.listName = oldName.subSequence(0, oldName.length() - 2 - spaceLeft) + String.valueOf(System.currentTimeMillis() % 99); |
1431 1514 | } else { |
1432 1515 | entityPlayer.listName = oldName + String.valueOf(System.currentTimeMillis() % 99); |
1433 1516 | } |
1434 1517 | |
1435 1518 | return; |
1436 1519 | } |
1437 1520 | } |
1438 1521 | } |
1439 1522 | |
1523 + | |
1440 1524 | public File getWorldContainer() { |
1441 1525 | if (this.getServer().universe != null) { |
1442 1526 | return this.getServer().universe; |
1443 1527 | } |
1444 1528 | |
1445 1529 | if (container == null) { |
1446 1530 | container = new File(configuration.getString("settings.world-container", ".")); |
1447 1531 | } |
1448 1532 | |
1449 1533 | return container; |
1450 1534 | } |
1451 1535 | |
1536 + | |
1452 1537 | public OfflinePlayer[] getOfflinePlayers() { |
1453 1538 | WorldNBTStorage storage = (WorldNBTStorage) console.worlds.get(0).getDataManager(); |
1454 1539 | String[] files = storage.getPlayerDir().list(new DatFileFilter()); |
1455 1540 | Set<OfflinePlayer> players = new HashSet<OfflinePlayer>(); |
1456 1541 | |
1457 1542 | for (String file : files) { |
1458 1543 | try { |
1459 1544 | players.add(getOfflinePlayer(UUID.fromString(file.substring(0, file.length() - 4)))); |
1460 1545 | } catch (IllegalArgumentException ex) { |
1461 1546 | // Who knows what is in this directory, just ignore invalid files |
1462 1547 | } |
1463 1548 | } |
1464 1549 | |
1465 - | players.addAll(Arrays.asList(getOnlinePlayers())); |
1550 + | players.addAll(getOnlinePlayers()); |
1466 1551 | |
1467 1552 | return players.toArray(new OfflinePlayer[players.size()]); |
1468 1553 | } |
1469 1554 | |
1555 + | |
1470 1556 | public Messenger getMessenger() { |
1471 1557 | return messenger; |
1472 1558 | } |
1473 1559 | |
1560 + | |
1474 1561 | public void sendPluginMessage(Plugin source, String channel, byte[] message) { |
1475 1562 | StandardMessenger.validatePluginMessage(getMessenger(), source, channel, message); |
1476 1563 | |
1477 1564 | for (Player player : getOnlinePlayers()) { |
1478 1565 | player.sendPluginMessage(source, channel, message); |
1479 1566 | } |
1480 1567 | } |
1481 1568 | |
1569 + | |
1482 1570 | public Set<String> getListeningPluginChannels() { |
1483 1571 | Set<String> result = new HashSet<String>(); |
1484 1572 | |
1485 1573 | for (Player player : getOnlinePlayers()) { |
1486 1574 | result.addAll(player.getListeningPluginChannels()); |
1487 1575 | } |
1488 1576 | |
1489 1577 | return result; |
1490 1578 | } |
1491 1579 | |
1492 1580 | public void onPlayerJoin(Player player) { |
1493 1581 | if ((updater.isEnabled()) && (updater.getCurrent() != null) && (player.hasPermission(Server.BROADCAST_CHANNEL_ADMINISTRATIVE))) { |
1494 1582 | if ((updater.getCurrent().isBroken()) && (updater.getOnBroken().contains(AutoUpdater.WARN_OPERATORS))) { |
1495 1583 | player.sendMessage(ChatColor.DARK_RED + "The version of CraftBukkit that this server is running is known to be broken. Please consider updating to the latest version at dl.bukkit.org."); |
1496 1584 | } else if ((updater.isUpdateAvailable()) && (updater.getOnUpdate().contains(AutoUpdater.WARN_OPERATORS))) { |
1497 1585 | player.sendMessage(ChatColor.DARK_PURPLE + "The version of CraftBukkit that this server is running is out of date. Please consider updating to the latest version at dl.bukkit.org."); |
1498 1586 | } |
1499 1587 | } |
1500 1588 | } |
1501 1589 | |
1590 + | |
1502 1591 | public Inventory createInventory(InventoryHolder owner, InventoryType type) { |
1503 1592 | // TODO: Create the appropriate type, rather than Custom? |
1504 1593 | return new CraftInventoryCustom(owner, type); |
1505 1594 | } |
1506 1595 | |
1596 + | |
1507 1597 | public Inventory createInventory(InventoryHolder owner, InventoryType type, String title) { |
1508 1598 | return new CraftInventoryCustom(owner, type, title); |
1509 1599 | } |
1510 1600 | |
1601 + | |
1511 1602 | public Inventory createInventory(InventoryHolder owner, int size) throws IllegalArgumentException { |
1512 1603 | Validate.isTrue(size % 9 == 0, "Chests must have a size that is a multiple of 9!"); |
1513 1604 | return new CraftInventoryCustom(owner, size); |
1514 1605 | } |
1515 1606 | |
1607 + | |
1516 1608 | public Inventory createInventory(InventoryHolder owner, int size, String title) throws IllegalArgumentException { |
1517 1609 | Validate.isTrue(size % 9 == 0, "Chests must have a size that is a multiple of 9!"); |
1518 1610 | return new CraftInventoryCustom(owner, size, title); |
1519 1611 | } |
1520 1612 | |
1613 + | |
1521 1614 | public HelpMap getHelpMap() { |
1522 1615 | return helpMap; |
1523 1616 | } |
1524 1617 | |
1525 1618 | public SimpleCommandMap getCommandMap() { |
1526 1619 | return commandMap; |
1527 1620 | } |
1528 1621 | |
1622 + | |
1529 1623 | public int getMonsterSpawnLimit() { |
1530 1624 | return monsterSpawn; |
1531 1625 | } |
1532 1626 | |
1627 + | |
1533 1628 | public int getAnimalSpawnLimit() { |
1534 1629 | return animalSpawn; |
1535 1630 | } |
1536 1631 | |
1632 + | |
1537 1633 | public int getWaterAnimalSpawnLimit() { |
1538 1634 | return waterAnimalSpawn; |
1539 1635 | } |
1540 1636 | |
1637 + | |
1541 1638 | public int getAmbientSpawnLimit() { |
1542 1639 | return ambientSpawn; |
1543 1640 | } |
1544 1641 | |
1642 + | |
1545 1643 | public boolean isPrimaryThread() { |
1546 1644 | return Thread.currentThread().equals(console.primaryThread); |
1547 1645 | } |
1548 1646 | |
1647 + | |
1549 1648 | public String getMotd() { |
1550 1649 | return console.getMotd(); |
1551 1650 | } |
1552 1651 | |
1652 + | |
1553 1653 | public WarningState getWarningState() { |
1554 1654 | return warningState; |
1555 1655 | } |
1556 1656 | |
1557 1657 | public List<String> tabComplete(net.minecraft.server.ICommandListener sender, String message) { |
1558 1658 | if (!(sender instanceof EntityPlayer)) { |
1559 1659 | return ImmutableList.of(); |
1560 1660 | } |
1561 1661 | |
1562 1662 | Player player = ((EntityPlayer) sender).getBukkitEntity(); |
1573 1673 | completions = getCommandMap().tabComplete(player, message.substring(1)); |
1574 1674 | } catch (CommandException ex) { |
1575 1675 | player.sendMessage(ChatColor.RED + "An internal error occurred while attempting to tab-complete this command"); |
1576 1676 | getLogger().log(Level.SEVERE, "Exception when " + player.getName() + " attempted to tab complete " + message, ex); |
1577 1677 | } |
1578 1678 | |
1579 1679 | return completions == null ? ImmutableList.<String>of() : completions; |
1580 1680 | } |
1581 1681 | |
1582 1682 | public List<String> tabCompleteChat(Player player, String message) { |
1583 - | Player[] players = getOnlinePlayers(); |
1584 1683 | List<String> completions = new ArrayList<String>(); |
1585 1684 | PlayerChatTabCompleteEvent event = new PlayerChatTabCompleteEvent(player, message, completions); |
1586 1685 | String token = event.getLastToken(); |
1587 - | for (Player p : players) { |
1686 + | for (Player p : getOnlinePlayers()) { |
1588 1687 | if (player.canSee(p) && StringUtil.startsWithIgnoreCase(p.getName(), token)) { |
1589 1688 | completions.add(p.getName()); |
1590 1689 | } |
1591 1690 | } |
1592 1691 | pluginManager.callEvent(event); |
1593 1692 | |
1594 1693 | Iterator<?> it = completions.iterator(); |
1595 1694 | while (it.hasNext()) { |
1596 1695 | Object current = it.next(); |
1597 1696 | if (!(current instanceof String)) { |
1598 1697 | // Sanity |
1599 1698 | it.remove(); |
1600 1699 | } |
1601 1700 | } |
1602 1701 | Collections.sort(completions, String.CASE_INSENSITIVE_ORDER); |
1603 1702 | return completions; |
1604 1703 | } |
1605 1704 | |
1705 + | |
1606 1706 | public CraftItemFactory getItemFactory() { |
1607 1707 | return CraftItemFactory.instance(); |
1608 1708 | } |
1609 1709 | |
1710 + | |
1610 1711 | public CraftScoreboardManager getScoreboardManager() { |
1611 1712 | return scoreboardManager; |
1612 1713 | } |
1613 1714 | |
1614 1715 | public void checkSaveState() { |
1615 1716 | if (this.playerCommandState || this.printSaveWarning || this.console.autosavePeriod <= 0) { |
1616 1717 | return; |
1617 1718 | } |
1618 1719 | this.printSaveWarning = true; |
1619 1720 | getLogger().log(Level.WARNING, "A manual (plugin-induced) save has been detected while server is configured to auto-save. This may affect performance.", warningState == WarningState.ON ? new Throwable() : null); |
1647 1748 | ByteBuf bytebuf = Unpooled.buffer(); |
1648 1749 | |
1649 1750 | Validate.isTrue(image.getWidth() == 64, "Must be 64 pixels wide"); |
1650 1751 | Validate.isTrue(image.getHeight() == 64, "Must be 64 pixels high"); |
1651 1752 | ImageIO.write(image, "PNG", new ByteBufOutputStream(bytebuf)); |
1652 1753 | ByteBuf bytebuf1 = Base64.encode(bytebuf); |
1653 1754 | |
1654 1755 | return new CraftIconCache("data:image/png;base64," + bytebuf1.toString(Charsets.UTF_8)); |
1655 1756 | } |
1656 1757 | |
1758 + | |
1657 1759 | public void setIdleTimeout(int threshold) { |
1658 1760 | console.setIdleTimeout(threshold); |
1659 1761 | } |
1660 1762 | |
1763 + | |
1661 1764 | public int getIdleTimeout() { |
1662 1765 | return console.getIdleTimeout(); |
1663 1766 | } |
1664 1767 | |
1665 1768 | |
1666 1769 | |
1667 1770 | public UnsafeValues getUnsafe() { |
1668 1771 | return CraftMagicNumbers.INSTANCE; |
1669 1772 | } |
1670 1773 | } |