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