001 package net.minecraft.server; 002 003 import cpw.mods.fml.common.Side; 004 import cpw.mods.fml.common.asm.SideOnly; 005 import java.awt.GraphicsEnvironment; 006 import java.io.File; 007 import java.io.IOException; 008 import java.security.KeyPair; 009 import java.text.SimpleDateFormat; 010 import java.util.ArrayList; 011 import java.util.Date; 012 import java.util.Hashtable; 013 import java.util.Iterator; 014 import java.util.List; 015 import java.util.logging.Level; 016 import java.util.logging.Logger; 017 import cpw.mods.fml.common.FMLCommonHandler; 018 import cpw.mods.fml.relauncher.ArgsWrapper; 019 import cpw.mods.fml.relauncher.FMLRelauncher; 020 import net.minecraft.src.AnvilSaveConverter; 021 import net.minecraft.src.AxisAlignedBB; 022 import net.minecraft.src.CallableIsServerModded; 023 import net.minecraft.src.CallablePlayers; 024 import net.minecraft.src.CallableServerProfiler; 025 import net.minecraft.src.ChunkCoordinates; 026 import net.minecraft.src.CommandBase; 027 import net.minecraft.src.ConvertProgressUpdater; 028 import net.minecraft.src.CrashReport; 029 import net.minecraft.src.DedicatedServer; 030 import net.minecraft.src.DemoWorldServer; 031 import net.minecraft.src.EnumGameType; 032 import net.minecraft.src.ICommandManager; 033 import net.minecraft.src.ICommandSender; 034 import net.minecraft.src.IPlayerUsage; 035 import net.minecraft.src.IProgressUpdate; 036 import net.minecraft.src.ISaveFormat; 037 import net.minecraft.src.ISaveHandler; 038 import net.minecraft.src.IUpdatePlayerListBox; 039 import net.minecraft.src.MathHelper; 040 import net.minecraft.src.MinecraftException; 041 import net.minecraft.src.NetworkListenThread; 042 import net.minecraft.src.Packet; 043 import net.minecraft.src.Packet4UpdateTime; 044 import net.minecraft.src.PlayerUsageSnooper; 045 import net.minecraft.src.Profiler; 046 import net.minecraft.src.RConConsoleSource; 047 import net.minecraft.src.ReportedException; 048 import net.minecraft.src.ServerCommandManager; 049 import net.minecraft.src.ServerConfigurationManager; 050 import net.minecraft.src.StatList; 051 import net.minecraft.src.StringTranslate; 052 import net.minecraft.src.StringUtils; 053 import net.minecraft.src.ThreadDedicatedServer; 054 import net.minecraft.src.ThreadServerApplication; 055 import net.minecraft.src.Vec3; 056 import net.minecraft.src.WorldInfo; 057 import net.minecraft.src.WorldManager; 058 import net.minecraft.src.WorldServer; 059 import net.minecraft.src.WorldServerMulti; 060 import net.minecraft.src.WorldSettings; 061 import net.minecraft.src.WorldType; 062 import net.minecraftforge.common.DimensionManager; 063 import net.minecraftforge.common.MinecraftForge; 064 import net.minecraftforge.event.world.WorldEvent; 065 066 public abstract class MinecraftServer implements Runnable, IPlayerUsage, ICommandSender 067 { 068 /** The logging system. */ 069 public static Logger logger = Logger.getLogger("Minecraft"); 070 071 /** Instance of Minecraft Server. */ 072 private static MinecraftServer mcServer = null; 073 private final ISaveFormat anvilConverterForAnvilFile; 074 075 /** The PlayerUsageSnooper instance. */ 076 private final PlayerUsageSnooper usageSnooper = new PlayerUsageSnooper("server", this); 077 private final File anvilFile; 078 079 /** List of names of players who are online. */ 080 private final List playersOnline = new ArrayList(); 081 private final ICommandManager commandManager; 082 public final Profiler theProfiler = new Profiler(); 083 084 /** The server's hostname. */ 085 private String hostname; 086 087 /** The server's port. */ 088 private int serverPort = -1; 089 090 /** The server world instances. */ 091 public WorldServer[] worldServers; 092 093 /** The ServerConfigurationManager instance. */ 094 private ServerConfigurationManager serverConfigManager; 095 096 /** 097 * Indicates whether the server is running or not. Set to false to initiate a shutdown. 098 */ 099 private boolean serverRunning = true; 100 101 /** Indicates to other classes that the server is safely stopped. */ 102 private boolean serverStopped = false; 103 104 /** Incremented every tick. */ 105 private int tickCounter = 0; 106 107 /** 108 * The task the server is currently working on(and will output on outputPercentRemaining). 109 */ 110 public String currentTask; 111 112 /** The percentage of the current task finished so far. */ 113 public int percentDone; 114 115 /** True if the server is in online mode. */ 116 private boolean onlineMode; 117 118 /** True if the server has animals turned on. */ 119 private boolean canSpawnAnimals; 120 private boolean canSpawnNPCs; 121 122 /** Indicates whether PvP is active on the server or not. */ 123 private boolean pvpEnabled; 124 125 /** Determines if flight is allowed or not. */ 126 private boolean allowFlight; 127 128 /** The server MOTD string. */ 129 private String motd; 130 131 /** Maximum build height. */ 132 private int buildLimit; 133 private long lastSentPacketID; 134 private long lastSentPacketSize; 135 private long lastReceivedID; 136 private long lastReceivedSize; 137 public final long[] sentPacketCountArray = new long[100]; 138 public final long[] sentPacketSizeArray = new long[100]; 139 public final long[] receivedPacketCountArray = new long[100]; 140 public final long[] receivedPacketSizeArray = new long[100]; 141 public final long[] tickTimeArray = new long[100]; 142 143 /** Stats are [dimension][tick%100] system.nanoTime is stored. */ 144 //public long[][] timeOfLastDimensionTick; 145 public Hashtable<Integer, long[]> worldTickTimes = new Hashtable<Integer, long[]>(); 146 public int spawnProtectionSize = 16; 147 private KeyPair serverKeyPair; 148 149 /** Username of the server owner (for integrated servers) */ 150 private String serverOwner; 151 private String folderName; 152 @SideOnly(Side.CLIENT) 153 private String worldName; 154 private boolean isDemo; 155 private boolean enableBonusChest; 156 157 /** 158 * If true, there is no need to save chunks or stop the server, because that is already being done. 159 */ 160 private boolean worldIsBeingDeleted; 161 private String texturePack = ""; 162 private boolean serverIsRunning = false; 163 164 /** 165 * Set when warned for "Can't keep up", which triggers again after 15 seconds. 166 */ 167 private long timeOfLastWarning; 168 private String userMessage; 169 private boolean startProfiling; 170 171 public MinecraftServer(File par1File) 172 { 173 mcServer = this; 174 this.anvilFile = par1File; 175 this.commandManager = new ServerCommandManager(); 176 this.anvilConverterForAnvilFile = new AnvilSaveConverter(par1File); 177 } 178 179 /** 180 * Initialises the server and starts it. 181 */ 182 protected abstract boolean startServer() throws IOException; 183 184 protected void convertMapIfNeeded(String par1Str) 185 { 186 if (this.getActiveAnvilConverter().isOldMapFormat(par1Str)) 187 { 188 logger.info("Converting map!"); 189 this.setUserMessage("menu.convertingLevel"); 190 this.getActiveAnvilConverter().convertMapFormat(par1Str, new ConvertProgressUpdater(this)); 191 } 192 } 193 194 /** 195 * Typically "menu.convertingLevel", "menu.loadingLevel" or others. 196 */ 197 protected synchronized void setUserMessage(String par1Str) 198 { 199 this.userMessage = par1Str; 200 } 201 202 @SideOnly(Side.CLIENT) 203 204 public synchronized String getUserMessage() 205 { 206 return this.userMessage; 207 } 208 209 protected void loadAllWorlds(String par1Str, String par2Str, long par3, WorldType par5WorldType) 210 { 211 this.convertMapIfNeeded(par1Str); 212 this.setUserMessage("menu.loadingLevel"); 213 ISaveHandler var6 = this.anvilConverterForAnvilFile.getSaveLoader(par1Str, true); 214 WorldInfo var8 = var6.loadWorldInfo(); 215 WorldSettings var7; 216 217 if (var8 == null) 218 { 219 var7 = new WorldSettings(par3, this.getGameType(), this.canStructuresSpawn(), this.isHardcore(), par5WorldType); 220 } 221 else 222 { 223 var7 = new WorldSettings(var8); 224 } 225 226 if (this.enableBonusChest) 227 { 228 var7.enableBonusChest(); 229 } 230 231 WorldServer overWorld = (isDemo() ? new DemoWorldServer(this, var6, par2Str, 0, theProfiler) : new WorldServer(this, var6, par2Str, 0, var7, theProfiler)); 232 for (int dim : DimensionManager.getStaticDimensionIDs()) 233 { 234 WorldServer world = (dim == 0 ? overWorld : new WorldServerMulti(this, var6, par2Str, dim, var7, overWorld, theProfiler)); 235 world.addWorldAccess(new WorldManager(this, world)); 236 237 if (!this.isSinglePlayer()) 238 { 239 world.getWorldInfo().setGameType(this.getGameType()); 240 } 241 242 this.serverConfigManager.setPlayerManager(this.worldServers); 243 MinecraftForge.EVENT_BUS.post(new WorldEvent.Load(world)); 244 } 245 246 this.serverConfigManager.setPlayerManager(new WorldServer[]{ overWorld }); 247 this.setDifficultyForAllWorlds(this.getDifficulty()); 248 this.initialWorldChunkLoad(); 249 } 250 251 protected void initialWorldChunkLoad() 252 { 253 short var1 = 196; 254 long var2 = System.currentTimeMillis(); 255 this.setUserMessage("menu.generatingTerrain"); 256 257 for (int var4 = 0; var4 < 1; ++var4) 258 { 259 logger.info("Preparing start region for level " + var4); 260 WorldServer var5 = this.worldServers[var4]; 261 ChunkCoordinates var6 = var5.getSpawnPoint(); 262 263 for (int var7 = -var1; var7 <= var1 && this.isServerRunning(); var7 += 16) 264 { 265 for (int var8 = -var1; var8 <= var1 && this.isServerRunning(); var8 += 16) 266 { 267 long var9 = System.currentTimeMillis(); 268 269 if (var9 < var2) 270 { 271 var2 = var9; 272 } 273 274 if (var9 > var2 + 1000L) 275 { 276 int var11 = (var1 * 2 + 1) * (var1 * 2 + 1); 277 int var12 = (var7 + var1) * (var1 * 2 + 1) + var8 + 1; 278 this.outputPercentRemaining("Preparing spawn area", var12 * 100 / var11); 279 var2 = var9; 280 } 281 282 var5.theChunkProviderServer.loadChunk(var6.posX + var7 >> 4, var6.posZ + var8 >> 4); 283 284 while (var5.updatingLighting() && this.isServerRunning()) 285 { 286 ; 287 } 288 } 289 } 290 } 291 292 this.clearCurrentTask(); 293 } 294 295 public abstract boolean canStructuresSpawn(); 296 297 public abstract EnumGameType getGameType(); 298 299 /** 300 * Defaults to "1" (Easy) for the dedicated server, defaults to "2" (Normal) on the client. 301 */ 302 public abstract int getDifficulty(); 303 304 /** 305 * Defaults to false. 306 */ 307 public abstract boolean isHardcore(); 308 309 /** 310 * Used to display a percent remaining given text and the percentage. 311 */ 312 protected void outputPercentRemaining(String par1Str, int par2) 313 { 314 this.currentTask = par1Str; 315 this.percentDone = par2; 316 logger.info(par1Str + ": " + par2 + "%"); 317 } 318 319 /** 320 * Set current task to null and set its percentage to 0. 321 */ 322 protected void clearCurrentTask() 323 { 324 this.currentTask = null; 325 this.percentDone = 0; 326 } 327 328 /** 329 * par1 indicates if a log message should be output. 330 */ 331 protected void saveAllWorlds(boolean par1) 332 { 333 if (!this.worldIsBeingDeleted) 334 { 335 WorldServer[] var2 = this.worldServers; 336 int var3 = var2.length; 337 338 for (int var4 = 0; var4 < var3; ++var4) 339 { 340 WorldServer var5 = var2[var4]; 341 342 if (var5 != null) 343 { 344 if (!par1) 345 { 346 logger.info("Saving chunks for level \'" + var5.getWorldInfo().getWorldName() + "\'/" + var5.provider.getDimensionName()); 347 } 348 349 try 350 { 351 var5.saveAllChunks(true, (IProgressUpdate)null); 352 } 353 catch (MinecraftException var7) 354 { 355 logger.warning(var7.getMessage()); 356 } 357 } 358 } 359 } 360 } 361 362 /** 363 * Saves all necessary data as preparation for stopping the server. 364 */ 365 public void stopServer() 366 { 367 if (!this.worldIsBeingDeleted) 368 { 369 logger.info("Stopping server"); 370 371 if (this.getNetworkThread() != null) 372 { 373 this.getNetworkThread().stopListening(); 374 } 375 376 if (this.serverConfigManager != null) 377 { 378 logger.info("Saving players"); 379 this.serverConfigManager.saveAllPlayerData(); 380 this.serverConfigManager.removeAllPlayers(); 381 } 382 383 logger.info("Saving worlds"); 384 this.saveAllWorlds(false); 385 WorldServer[] var1 = this.worldServers; 386 int var2 = var1.length; 387 388 for (int var3 = 0; var3 < var2; ++var3) 389 { 390 WorldServer var4 = var1[var3]; 391 MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(var4)); 392 var4.flush(); 393 DimensionManager.setWorld(var4.provider.dimensionId, null); 394 } 395 396 if (this.usageSnooper != null && this.usageSnooper.isSnooperRunning()) 397 { 398 this.usageSnooper.stopSnooper(); 399 } 400 } 401 } 402 403 /** 404 * "getHostname" is already taken, but both return the hostname. 405 */ 406 public String getServerHostname() 407 { 408 return this.hostname; 409 } 410 411 public void setHostname(String par1Str) 412 { 413 this.hostname = par1Str; 414 } 415 416 public boolean isServerRunning() 417 { 418 return this.serverRunning; 419 } 420 421 /** 422 * Sets the serverRunning variable to false, in order to get the server to shut down. 423 */ 424 public void initiateShutdown() 425 { 426 this.serverRunning = false; 427 } 428 429 public void run() 430 { 431 try 432 { 433 if (this.startServer()) 434 { 435 FMLCommonHandler.instance().handleServerStarted(); 436 long var1 = System.currentTimeMillis(); 437 438 FMLCommonHandler.instance().onWorldLoadTick(worldServers); 439 440 for (long var50 = 0L; this.serverRunning; this.serverIsRunning = true) 441 { 442 long var5 = System.currentTimeMillis(); 443 long var7 = var5 - var1; 444 445 if (var7 > 2000L && var1 - this.timeOfLastWarning >= 15000L) 446 { 447 logger.warning("Can\'t keep up! Did the system time change, or is the server overloaded?"); 448 var7 = 2000L; 449 this.timeOfLastWarning = var1; 450 } 451 452 if (var7 < 0L) 453 { 454 logger.warning("Time ran backwards! Did the system time change?"); 455 var7 = 0L; 456 } 457 458 var50 += var7; 459 var1 = var5; 460 461 if (this.worldServers[0].areAllPlayersAsleep()) 462 { 463 this.tick(); 464 var50 = 0L; 465 } 466 else 467 { 468 while (var50 > 50L) 469 { 470 var50 -= 50L; 471 this.tick(); 472 } 473 } 474 475 Thread.sleep(1L); 476 } 477 FMLCommonHandler.instance().handleServerStopping(); 478 } 479 else 480 { 481 this.finalTick((CrashReport)null); 482 } 483 } 484 catch (Throwable var48) 485 { 486 var48.printStackTrace(); 487 logger.log(Level.SEVERE, "Encountered an unexpected exception " + var48.getClass().getSimpleName(), var48); 488 CrashReport var2 = null; 489 490 if (var48 instanceof ReportedException) 491 { 492 var2 = this.addServerInfoToCrashReport(((ReportedException)var48).getTheReportedExceptionCrashReport()); 493 } 494 else 495 { 496 var2 = this.addServerInfoToCrashReport(new CrashReport("Exception in server tick loop", var48)); 497 } 498 499 File var3 = new File(new File(this.getDataDirectory(), "crash-reports"), "crash-" + (new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss")).format(new Date()) + "-server.txt"); 500 501 if (var2.saveToFile(var3)) 502 { 503 logger.severe("This crash report has been saved to: " + var3.getAbsolutePath()); 504 } 505 else 506 { 507 logger.severe("We were unable to save this crash report to disk."); 508 } 509 510 this.finalTick(var2); 511 } 512 finally 513 { 514 try 515 { 516 this.stopServer(); 517 this.serverStopped = true; 518 } 519 catch (Throwable var46) 520 { 521 var46.printStackTrace(); 522 } 523 finally 524 { 525 this.systemExitNow(); 526 } 527 } 528 } 529 530 protected File getDataDirectory() 531 { 532 return new File("."); 533 } 534 535 /** 536 * Called on exit from the main run() loop. 537 */ 538 protected void finalTick(CrashReport par1CrashReport) {} 539 540 /** 541 * Directly calls System.exit(0), instantly killing the program. 542 */ 543 protected void systemExitNow() {} 544 545 /** 546 * Main function called by run() every loop. 547 */ 548 public void tick() 549 { 550 FMLCommonHandler.instance().rescheduleTicks(Side.SERVER); 551 long var1 = System.nanoTime(); 552 AxisAlignedBB.getAABBPool().cleanPool(); 553 Vec3.getVec3Pool().clear(); 554 FMLCommonHandler.instance().onPreServerTick(); 555 ++this.tickCounter; 556 557 if (this.startProfiling) 558 { 559 this.startProfiling = false; 560 this.theProfiler.profilingEnabled = true; 561 this.theProfiler.clearProfiling(); 562 } 563 564 this.theProfiler.startSection("root"); 565 this.updateTimeLightAndEntities(); 566 567 if (this.tickCounter % 900 == 0) 568 { 569 this.theProfiler.startSection("save"); 570 this.serverConfigManager.saveAllPlayerData(); 571 this.saveAllWorlds(true); 572 this.theProfiler.endSection(); 573 } 574 575 this.theProfiler.startSection("tallying"); 576 this.tickTimeArray[this.tickCounter % 100] = System.nanoTime() - var1; 577 this.sentPacketCountArray[this.tickCounter % 100] = Packet.sentID - this.lastSentPacketID; 578 this.lastSentPacketID = Packet.sentID; 579 this.sentPacketSizeArray[this.tickCounter % 100] = Packet.sentSize - this.lastSentPacketSize; 580 this.lastSentPacketSize = Packet.sentSize; 581 this.receivedPacketCountArray[this.tickCounter % 100] = Packet.receivedID - this.lastReceivedID; 582 this.lastReceivedID = Packet.receivedID; 583 this.receivedPacketSizeArray[this.tickCounter % 100] = Packet.receivedSize - this.lastReceivedSize; 584 this.lastReceivedSize = Packet.receivedSize; 585 this.theProfiler.endSection(); 586 this.theProfiler.startSection("snooper"); 587 588 if (!this.usageSnooper.isSnooperRunning() && this.tickCounter > 100) 589 { 590 this.usageSnooper.startSnooper(); 591 } 592 593 if (this.tickCounter % 6000 == 0) 594 { 595 this.usageSnooper.addMemoryStatsToSnooper(); 596 } 597 598 this.theProfiler.endSection(); 599 this.theProfiler.endSection(); 600 FMLCommonHandler.instance().onPostServerTick(); 601 } 602 603 public void updateTimeLightAndEntities() 604 { 605 this.theProfiler.startSection("levels"); 606 607 for (Integer id : DimensionManager.getIDs()) 608 { 609 long var2 = System.nanoTime(); 610 611 if (id == 0 || this.getAllowNether()) 612 { 613 WorldServer var4 = DimensionManager.getWorld(id); 614 this.theProfiler.startSection(var4.getWorldInfo().getWorldName()); 615 616 if (this.tickCounter % 20 == 0) 617 { 618 this.theProfiler.startSection("timeSync"); 619 this.serverConfigManager.sendPacketToAllPlayersInDimension(new Packet4UpdateTime(var4.getWorldTime()), var4.provider.dimensionId); 620 this.theProfiler.endSection(); 621 } 622 623 this.theProfiler.startSection("tick"); 624 FMLCommonHandler.instance().onPreWorldTick(var4); 625 var4.tick(); 626 FMLCommonHandler.instance().onPostWorldTick(var4); 627 this.theProfiler.endStartSection("lights"); 628 629 while (true) 630 { 631 if (!var4.updatingLighting()) 632 { 633 this.theProfiler.endSection(); 634 var4.updateEntities(); 635 this.theProfiler.startSection("tracker"); 636 var4.getEntityTracker().updateTrackedEntities(); 637 this.theProfiler.endSection(); 638 this.theProfiler.endSection(); 639 break; 640 } 641 } 642 } 643 644 worldTickTimes.get(id)[this.tickCounter % 100] = System.nanoTime() - var2; 645 } 646 647 this.theProfiler.endStartSection("dim_unloading"); 648 DimensionManager.unloadWorlds(worldTickTimes); 649 this.theProfiler.endStartSection("connection"); 650 this.getNetworkThread().networkTick(); 651 this.theProfiler.endStartSection("players"); 652 this.serverConfigManager.sendPlayerInfoToAllPlayers(); 653 this.theProfiler.endStartSection("tickables"); 654 Iterator var5 = this.playersOnline.iterator(); 655 656 while (var5.hasNext()) 657 { 658 IUpdatePlayerListBox var6 = (IUpdatePlayerListBox)var5.next(); 659 var6.update(); 660 } 661 662 this.theProfiler.endSection(); 663 } 664 665 public boolean getAllowNether() 666 { 667 return true; 668 } 669 670 public void startServerThread() 671 { 672 (new ThreadServerApplication(this, "Server thread")).start(); 673 } 674 675 /** 676 * Returns a File object from the specified string. 677 */ 678 public File getFile(String par1Str) 679 { 680 return new File(this.getDataDirectory(), par1Str); 681 } 682 683 /** 684 * Logs the message with a level of INFO. 685 */ 686 public void logInfo(String par1Str) 687 { 688 logger.info(par1Str); 689 } 690 691 /** 692 * Logs the message with a level of WARN. 693 */ 694 public void logWarning(String par1Str) 695 { 696 logger.warning(par1Str); 697 } 698 699 /** 700 * Gets the worldServer by the given dimension. 701 */ 702 public WorldServer worldServerForDimension(int par1) 703 { 704 WorldServer ret = DimensionManager.getWorld(par1); 705 if (ret == null) { 706 DimensionManager.initDimension(par1); 707 ret = DimensionManager.getWorld(par1); 708 } 709 return ret; 710 } 711 712 @SideOnly(Side.SERVER) 713 714 /** 715 * Adds a player's name to the list of online players. 716 */ 717 public void addToOnlinePlayerList(IUpdatePlayerListBox par1IUpdatePlayerListBox) 718 { 719 this.playersOnline.add(par1IUpdatePlayerListBox); 720 } 721 722 /** 723 * Returns the server's hostname. 724 */ 725 public String getHostname() 726 { 727 return this.hostname; 728 } 729 730 /** 731 * Never used, but "getServerPort" is already taken. 732 */ 733 public int getPort() 734 { 735 return this.serverPort; 736 } 737 738 /** 739 * minecraftServer.getMOTD is used in 2 places instead (it is a non-virtual function which returns the same thing) 740 */ 741 public String getServerMOTD() 742 { 743 return this.motd; 744 } 745 746 /** 747 * Returns the server's Minecraft version as string. 748 */ 749 public String getMinecraftVersion() 750 { 751 return "1.3.2"; 752 } 753 754 /** 755 * Returns the number of players currently on the server. 756 */ 757 public int getCurrentPlayerCount() 758 { 759 return this.serverConfigManager.getCurrentPlayerCount(); 760 } 761 762 /** 763 * Returns the maximum number of players allowed on the server. 764 */ 765 public int getMaxPlayers() 766 { 767 return this.serverConfigManager.getMaxPlayers(); 768 } 769 770 /** 771 * Returns an array of the usernames of all the connected players. 772 */ 773 public String[] getAllUsernames() 774 { 775 return this.serverConfigManager.getAllUsernames(); 776 } 777 778 /** 779 * Used by RCon's Query in the form of "MajorServerMod 1.2.3: MyPlugin 1.3; AnotherPlugin 2.1; AndSoForth 1.0". 780 */ 781 public String getPlugins() 782 { 783 return ""; 784 } 785 786 public String executeCommand(String par1Str) 787 { 788 RConConsoleSource.consoleBuffer.resetLog(); 789 this.commandManager.executeCommand(RConConsoleSource.consoleBuffer, par1Str); 790 return RConConsoleSource.consoleBuffer.getChatBuffer(); 791 } 792 793 /** 794 * Returns true if debugging is enabled, false otherwise. 795 */ 796 public boolean isDebuggingEnabled() 797 { 798 return false; 799 } 800 801 /** 802 * Logs the error message with a level of SEVERE. 803 */ 804 public void logSevere(String par1Str) 805 { 806 logger.log(Level.SEVERE, par1Str); 807 } 808 809 /** 810 * If isDebuggingEnabled(), logs the message with a level of INFO. 811 */ 812 public void logDebug(String par1Str) 813 { 814 if (this.isDebuggingEnabled()) 815 { 816 logger.log(Level.INFO, par1Str); 817 } 818 } 819 820 public String getServerModName() 821 { 822 return "forge,fml"; 823 } 824 825 /** 826 * Adds the server info, including from theWorldServer, to the crash report. 827 */ 828 public CrashReport addServerInfoToCrashReport(CrashReport par1CrashReport) 829 { 830 par1CrashReport.addCrashSectionCallable("Is Modded", new CallableIsServerModded(this)); 831 par1CrashReport.addCrashSectionCallable("Profiler Position", new CallableServerProfiler(this)); 832 833 if (this.serverConfigManager != null) 834 { 835 par1CrashReport.addCrashSectionCallable("Player Count", new CallablePlayers(this)); 836 } 837 838 if (this.worldServers != null) 839 { 840 WorldServer[] var2 = this.worldServers; 841 int var3 = var2.length; 842 843 for (int var4 = 0; var4 < var3; ++var4) 844 { 845 WorldServer var5 = var2[var4]; 846 847 if (var5 != null) 848 { 849 var5.addWorldInfoToCrashReport(par1CrashReport); 850 } 851 } 852 } 853 854 return par1CrashReport; 855 } 856 857 /** 858 * If par2Str begins with /, then it searches for commands, otherwise it returns players. 859 */ 860 public List getPossibleCompletions(ICommandSender par1ICommandSender, String par2Str) 861 { 862 ArrayList var3 = new ArrayList(); 863 864 if (par2Str.startsWith("/")) 865 { 866 par2Str = par2Str.substring(1); 867 boolean var10 = !par2Str.contains(" "); 868 List var11 = this.commandManager.getPossibleCommands(par1ICommandSender, par2Str); 869 870 if (var11 != null) 871 { 872 Iterator var12 = var11.iterator(); 873 874 while (var12.hasNext()) 875 { 876 String var13 = (String)var12.next(); 877 878 if (var10) 879 { 880 var3.add("/" + var13); 881 } 882 else 883 { 884 var3.add(var13); 885 } 886 } 887 } 888 889 return var3; 890 } 891 else 892 { 893 String[] var4 = par2Str.split(" ", -1); 894 String var5 = var4[var4.length - 1]; 895 String[] var6 = this.serverConfigManager.getAllUsernames(); 896 int var7 = var6.length; 897 898 for (int var8 = 0; var8 < var7; ++var8) 899 { 900 String var9 = var6[var8]; 901 902 if (CommandBase.doesStringStartWith(var5, var9)) 903 { 904 var3.add(var9); 905 } 906 } 907 908 return var3; 909 } 910 } 911 912 /** 913 * Gets mcServer. 914 */ 915 public static MinecraftServer getServer() 916 { 917 return mcServer; 918 } 919 920 /** 921 * Gets the name of this command sender (usually username, but possibly "Rcon") 922 */ 923 public String getCommandSenderName() 924 { 925 return "Server"; 926 } 927 928 public void sendChatToPlayer(String par1Str) 929 { 930 logger.info(StringUtils.stripControlCodes(par1Str)); 931 } 932 933 /** 934 * Returns true if the command sender is allowed to use the given command. 935 */ 936 public boolean canCommandSenderUseCommand(String par1Str) 937 { 938 return true; 939 } 940 941 /** 942 * Translates and formats the given string key with the given arguments. 943 */ 944 public String translateString(String par1Str, Object ... par2ArrayOfObj) 945 { 946 return StringTranslate.getInstance().translateKeyFormat(par1Str, par2ArrayOfObj); 947 } 948 949 public ICommandManager getCommandManager() 950 { 951 return this.commandManager; 952 } 953 954 /** 955 * Gets KeyPair instanced in MinecraftServer. 956 */ 957 public KeyPair getKeyPair() 958 { 959 return this.serverKeyPair; 960 } 961 962 /** 963 * Gets serverPort. 964 */ 965 public int getServerPort() 966 { 967 return this.serverPort; 968 } 969 970 public void setServerPort(int par1) 971 { 972 this.serverPort = par1; 973 } 974 975 /** 976 * Returns the username of the server owner (for integrated servers) 977 */ 978 public String getServerOwner() 979 { 980 return this.serverOwner; 981 } 982 983 /** 984 * Sets the username of the owner of this server (in the case of an integrated server) 985 */ 986 public void setServerOwner(String par1Str) 987 { 988 this.serverOwner = par1Str; 989 } 990 991 public boolean isSinglePlayer() 992 { 993 return this.serverOwner != null; 994 } 995 996 public String getFolderName() 997 { 998 return this.folderName; 999 } 1000 1001 public void setFolderName(String par1Str) 1002 { 1003 this.folderName = par1Str; 1004 } 1005 1006 @SideOnly(Side.CLIENT) 1007 public void setWorldName(String par1Str) 1008 { 1009 this.worldName = par1Str; 1010 } 1011 1012 @SideOnly(Side.CLIENT) 1013 public String getWorldName() 1014 { 1015 return this.worldName; 1016 } 1017 1018 public void setKeyPair(KeyPair par1KeyPair) 1019 { 1020 this.serverKeyPair = par1KeyPair; 1021 } 1022 1023 public void setDifficultyForAllWorlds(int par1) 1024 { 1025 for (int var2 = 0; var2 < this.worldServers.length; ++var2) 1026 { 1027 WorldServer var3 = this.worldServers[var2]; 1028 1029 if (var3 != null) 1030 { 1031 if (var3.getWorldInfo().isHardcoreModeEnabled()) 1032 { 1033 var3.difficultySetting = 3; 1034 var3.setAllowedSpawnTypes(true, true); 1035 } 1036 else if (this.isSinglePlayer()) 1037 { 1038 var3.difficultySetting = par1; 1039 var3.setAllowedSpawnTypes(var3.difficultySetting > 0, true); 1040 } 1041 else 1042 { 1043 var3.difficultySetting = par1; 1044 var3.setAllowedSpawnTypes(this.allowSpawnMonsters(), this.canSpawnAnimals); 1045 } 1046 } 1047 } 1048 } 1049 1050 protected boolean allowSpawnMonsters() 1051 { 1052 return true; 1053 } 1054 1055 /** 1056 * Gets whether this is a demo or not. 1057 */ 1058 public boolean isDemo() 1059 { 1060 return this.isDemo; 1061 } 1062 1063 /** 1064 * Sets whether this is a demo or not. 1065 */ 1066 public void setDemo(boolean par1) 1067 { 1068 this.isDemo = par1; 1069 } 1070 1071 public void canCreateBonusChest(boolean par1) 1072 { 1073 this.enableBonusChest = par1; 1074 } 1075 1076 public ISaveFormat getActiveAnvilConverter() 1077 { 1078 return this.anvilConverterForAnvilFile; 1079 } 1080 1081 /** 1082 * WARNING : directly calls 1083 * getActiveAnvilConverter().deleteWorldDirectory(theWorldServer[0].getSaveHandler().getSaveDirectoryName()); 1084 */ 1085 public void deleteWorldAndStopServer() 1086 { 1087 this.worldIsBeingDeleted = true; 1088 this.getActiveAnvilConverter().flushCache(); 1089 1090 for (int var1 = 0; var1 < this.worldServers.length; ++var1) 1091 { 1092 WorldServer var2 = this.worldServers[var1]; 1093 1094 if (var2 != null) 1095 { 1096 MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(var2)); 1097 var2.flush(); 1098 } 1099 } 1100 1101 this.getActiveAnvilConverter().deleteWorldDirectory(this.worldServers[0].getSaveHandler().getSaveDirectoryName()); 1102 this.initiateShutdown(); 1103 } 1104 1105 public String getTexturePack() 1106 { 1107 return this.texturePack; 1108 } 1109 1110 public void setTexturePack(String par1Str) 1111 { 1112 this.texturePack = par1Str; 1113 } 1114 1115 public void addServerStatsToSnooper(PlayerUsageSnooper par1PlayerUsageSnooper) 1116 { 1117 par1PlayerUsageSnooper.addData("whitelist_enabled", Boolean.valueOf(false)); 1118 par1PlayerUsageSnooper.addData("whitelist_count", Integer.valueOf(0)); 1119 par1PlayerUsageSnooper.addData("players_current", Integer.valueOf(this.getCurrentPlayerCount())); 1120 par1PlayerUsageSnooper.addData("players_max", Integer.valueOf(this.getMaxPlayers())); 1121 par1PlayerUsageSnooper.addData("players_seen", Integer.valueOf(this.serverConfigManager.getAvailablePlayerDat().length)); 1122 par1PlayerUsageSnooper.addData("uses_auth", Boolean.valueOf(this.onlineMode)); 1123 par1PlayerUsageSnooper.addData("gui_state", this.getGuiEnabled() ? "enabled" : "disabled"); 1124 par1PlayerUsageSnooper.addData("avg_tick_ms", Integer.valueOf((int)(MathHelper.average(this.tickTimeArray) * 1.0E-6D))); 1125 par1PlayerUsageSnooper.addData("avg_sent_packet_count", Integer.valueOf((int)MathHelper.average(this.sentPacketCountArray))); 1126 par1PlayerUsageSnooper.addData("avg_sent_packet_size", Integer.valueOf((int)MathHelper.average(this.sentPacketSizeArray))); 1127 par1PlayerUsageSnooper.addData("avg_rec_packet_count", Integer.valueOf((int)MathHelper.average(this.receivedPacketCountArray))); 1128 par1PlayerUsageSnooper.addData("avg_rec_packet_size", Integer.valueOf((int)MathHelper.average(this.receivedPacketSizeArray))); 1129 int var2 = 0; 1130 1131 for (int var3 = 0; var3 < this.worldServers.length; ++var3) 1132 { 1133 if (this.worldServers[var3] != null) 1134 { 1135 WorldServer var4 = this.worldServers[var3]; 1136 WorldInfo var5 = var4.getWorldInfo(); 1137 par1PlayerUsageSnooper.addData("world[" + var2 + "][dimension]", Integer.valueOf(var4.provider.dimensionId)); 1138 par1PlayerUsageSnooper.addData("world[" + var2 + "][mode]", var5.getGameType()); 1139 par1PlayerUsageSnooper.addData("world[" + var2 + "][difficulty]", Integer.valueOf(var4.difficultySetting)); 1140 par1PlayerUsageSnooper.addData("world[" + var2 + "][hardcore]", Boolean.valueOf(var5.isHardcoreModeEnabled())); 1141 par1PlayerUsageSnooper.addData("world[" + var2 + "][generator_name]", var5.getTerrainType().getWorldTypeName()); 1142 par1PlayerUsageSnooper.addData("world[" + var2 + "][generator_version]", Integer.valueOf(var5.getTerrainType().getGeneratorVersion())); 1143 par1PlayerUsageSnooper.addData("world[" + var2 + "][height]", Integer.valueOf(this.buildLimit)); 1144 par1PlayerUsageSnooper.addData("world[" + var2 + "][chunks_loaded]", Integer.valueOf(var4.getChunkProvider().getLoadedChunkCount())); 1145 ++var2; 1146 } 1147 } 1148 1149 par1PlayerUsageSnooper.addData("worlds", Integer.valueOf(var2)); 1150 } 1151 1152 public void addServerTypeToSnooper(PlayerUsageSnooper par1PlayerUsageSnooper) 1153 { 1154 par1PlayerUsageSnooper.addData("singleplayer", Boolean.valueOf(this.isSinglePlayer())); 1155 par1PlayerUsageSnooper.addData("server_brand", this.getServerModName()); 1156 par1PlayerUsageSnooper.addData("gui_supported", GraphicsEnvironment.isHeadless() ? "headless" : "supported"); 1157 par1PlayerUsageSnooper.addData("dedicated", Boolean.valueOf(this.isDedicatedServer())); 1158 } 1159 1160 /** 1161 * Returns whether snooping is enabled or not. 1162 */ 1163 public boolean isSnooperEnabled() 1164 { 1165 return true; 1166 } 1167 1168 /** 1169 * This is checked to be 16 upon receiving the packet, otherwise the packet is ignored. 1170 */ 1171 public int textureSize() 1172 { 1173 return 16; 1174 } 1175 1176 public abstract boolean isDedicatedServer(); 1177 1178 public boolean isServerInOnlineMode() 1179 { 1180 return this.onlineMode; 1181 } 1182 1183 public void setOnlineMode(boolean par1) 1184 { 1185 this.onlineMode = par1; 1186 } 1187 1188 public boolean getCanSpawnAnimals() 1189 { 1190 return this.canSpawnAnimals; 1191 } 1192 1193 public void setCanSpawnAnimals(boolean par1) 1194 { 1195 this.canSpawnAnimals = par1; 1196 } 1197 1198 public boolean getCanSpawnNPCs() 1199 { 1200 return this.canSpawnNPCs; 1201 } 1202 1203 public void setCanSpawnNPCs(boolean par1) 1204 { 1205 this.canSpawnNPCs = par1; 1206 } 1207 1208 public boolean isPVPEnabled() 1209 { 1210 return this.pvpEnabled; 1211 } 1212 1213 public void setAllowPvp(boolean par1) 1214 { 1215 this.pvpEnabled = par1; 1216 } 1217 1218 public boolean isFlightAllowed() 1219 { 1220 return this.allowFlight; 1221 } 1222 1223 public void setAllowFlight(boolean par1) 1224 { 1225 this.allowFlight = par1; 1226 } 1227 1228 public String getMOTD() 1229 { 1230 return this.motd; 1231 } 1232 1233 public void setMOTD(String par1Str) 1234 { 1235 this.motd = par1Str; 1236 } 1237 1238 public int getBuildLimit() 1239 { 1240 return this.buildLimit; 1241 } 1242 1243 public void setBuildLimit(int par1) 1244 { 1245 this.buildLimit = par1; 1246 } 1247 1248 public boolean isServerStopped() 1249 { 1250 return this.serverStopped; 1251 } 1252 1253 public ServerConfigurationManager getConfigurationManager() 1254 { 1255 return this.serverConfigManager; 1256 } 1257 1258 public void setConfigurationManager(ServerConfigurationManager par1ServerConfigurationManager) 1259 { 1260 this.serverConfigManager = par1ServerConfigurationManager; 1261 } 1262 1263 /** 1264 * Sets the game type for all worlds. 1265 */ 1266 public void setGameType(EnumGameType par1EnumGameType) 1267 { 1268 for (int var2 = 0; var2 < this.worldServers.length; ++var2) 1269 { 1270 getServer().worldServers[var2].getWorldInfo().setGameType(par1EnumGameType); 1271 } 1272 } 1273 1274 public abstract NetworkListenThread getNetworkThread(); 1275 1276 @SideOnly(Side.CLIENT) 1277 public boolean serverIsInRunLoop() 1278 { 1279 return this.serverIsRunning; 1280 } 1281 1282 public boolean getGuiEnabled() 1283 { 1284 return false; 1285 } 1286 1287 /** 1288 * On dedicated does nothing. On integrated, sets commandsAllowedForAll, gameType and allows external connections. 1289 */ 1290 public abstract String shareToLAN(EnumGameType var1, boolean var2); 1291 1292 public int getTickCounter() 1293 { 1294 return this.tickCounter; 1295 } 1296 1297 public void enableProfiling() 1298 { 1299 this.startProfiling = true; 1300 } 1301 1302 @SideOnly(Side.CLIENT) 1303 public PlayerUsageSnooper getPlayerUsageSnooper() 1304 { 1305 return this.usageSnooper; 1306 } 1307 1308 /** 1309 * Gets the current player count, maximum player count, and player entity list. 1310 */ 1311 public static ServerConfigurationManager getServerConfigurationManager(MinecraftServer par0MinecraftServer) 1312 { 1313 return par0MinecraftServer.serverConfigManager; 1314 } 1315 1316 @SideOnly(Side.SERVER) 1317 public static void main(String[] par0ArrayOfStr) 1318 { 1319 FMLRelauncher.handleServerRelaunch(new ArgsWrapper(par0ArrayOfStr)); 1320 } 1321 @SideOnly(Side.SERVER) 1322 public static void fmlReentry(ArgsWrapper wrap) 1323 { 1324 String[] par0ArrayOfStr = wrap.args; 1325 StatList.func_75919_a(); 1326 1327 try 1328 { 1329 boolean var1 = !GraphicsEnvironment.isHeadless(); 1330 String var2 = null; 1331 String var3 = "."; 1332 String var4 = null; 1333 boolean var5 = false; 1334 boolean var6 = false; 1335 int var7 = -1; 1336 1337 for (int var8 = 0; var8 < par0ArrayOfStr.length; ++var8) 1338 { 1339 String var9 = par0ArrayOfStr[var8]; 1340 String var10 = var8 == par0ArrayOfStr.length - 1 ? null : par0ArrayOfStr[var8 + 1]; 1341 boolean var11 = false; 1342 1343 if (!var9.equals("nogui") && !var9.equals("--nogui")) 1344 { 1345 if (var9.equals("--port") && var10 != null) 1346 { 1347 var11 = true; 1348 1349 try 1350 { 1351 var7 = Integer.parseInt(var10); 1352 } 1353 catch (NumberFormatException var13) 1354 { 1355 ; 1356 } 1357 } 1358 else if (var9.equals("--singleplayer") && var10 != null) 1359 { 1360 var11 = true; 1361 var2 = var10; 1362 } 1363 else if (var9.equals("--universe") && var10 != null) 1364 { 1365 var11 = true; 1366 var3 = var10; 1367 } 1368 else if (var9.equals("--world") && var10 != null) 1369 { 1370 var11 = true; 1371 var4 = var10; 1372 } 1373 else if (var9.equals("--demo")) 1374 { 1375 var5 = true; 1376 } 1377 else if (var9.equals("--bonusChest")) 1378 { 1379 var6 = true; 1380 } 1381 } 1382 else 1383 { 1384 var1 = false; 1385 } 1386 1387 if (var11) 1388 { 1389 ++var8; 1390 } 1391 } 1392 1393 DedicatedServer var15 = new DedicatedServer(new File(var3)); 1394 1395 if (var2 != null) 1396 { 1397 var15.setServerOwner(var2); 1398 } 1399 1400 if (var4 != null) 1401 { 1402 var15.setFolderName(var4); 1403 } 1404 1405 if (var7 >= 0) 1406 { 1407 var15.setServerPort(var7); 1408 } 1409 1410 if (var5) 1411 { 1412 var15.setDemo(true); 1413 } 1414 1415 if (var6) 1416 { 1417 var15.canCreateBonusChest(true); 1418 } 1419 1420 if (var1) 1421 { 1422 var15.func_79001_aj(); 1423 } 1424 1425 var15.startServerThread(); 1426 Runtime.getRuntime().addShutdownHook(new ThreadDedicatedServer(var15)); 1427 } 1428 catch (Exception var14) 1429 { 1430 logger.log(Level.SEVERE, "Failed to start the minecraft server", var14); 1431 } 1432 } 1433 }