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