Java tutorial
package cn.nukkit; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.Calendar; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; import org.apache.commons.collections.BidiMap; import org.apache.commons.collections.bidimap.DualHashBidiMap; import com.google.common.base.Preconditions; import cn.nukkit.block.Block; import cn.nukkit.blockentity.BlockEntity; import cn.nukkit.blockentity.BlockEntityBeacon; import cn.nukkit.blockentity.BlockEntityBrewingStand; import cn.nukkit.blockentity.BlockEntityCauldron; import cn.nukkit.blockentity.BlockEntityChest; import cn.nukkit.blockentity.BlockEntityEnchantTable; import cn.nukkit.blockentity.BlockEntityEnderChest; import cn.nukkit.blockentity.BlockEntityFlowerPot; import cn.nukkit.blockentity.BlockEntityFurnace; import cn.nukkit.blockentity.BlockEntityItemFrame; import cn.nukkit.blockentity.BlockEntitySign; import cn.nukkit.blockentity.BlockEntitySkull; import cn.nukkit.command.Command; import cn.nukkit.command.CommandReader; import cn.nukkit.command.CommandSender; import cn.nukkit.command.ConsoleCommandSender; import cn.nukkit.command.PluginIdentifiableCommand; import cn.nukkit.command.SimpleCommandMap; import cn.nukkit.entity.Attribute; import cn.nukkit.entity.Entity; import cn.nukkit.entity.EntityHuman; import cn.nukkit.entity.boss.EntityElderGuardian; import cn.nukkit.entity.boss.EntityEnderDragon; import cn.nukkit.entity.boss.EntityWither; import cn.nukkit.entity.data.Skin; import cn.nukkit.entity.item.EntityBoat; import cn.nukkit.entity.item.EntityEnderCrystal; import cn.nukkit.entity.item.EntityExpBottle; import cn.nukkit.entity.item.EntityFallingBlock; import cn.nukkit.entity.item.EntityItem; import cn.nukkit.entity.item.EntityMinecartChest; import cn.nukkit.entity.item.EntityMinecartEmpty; import cn.nukkit.entity.item.EntityMinecartHopper; import cn.nukkit.entity.item.EntityMinecartTNT; import cn.nukkit.entity.item.EntityPainting; import cn.nukkit.entity.item.EntityPotion; import cn.nukkit.entity.item.EntityPrimedTNT; import cn.nukkit.entity.item.EntityXPOrb; import cn.nukkit.entity.mob.EntityBlaze; import cn.nukkit.entity.mob.EntityCaveSpider; import cn.nukkit.entity.mob.EntityCreeper; import cn.nukkit.entity.mob.EntityEnderman; import cn.nukkit.entity.mob.EntityEndermite; import cn.nukkit.entity.mob.EntityGhast; import cn.nukkit.entity.mob.EntityGuardian; import cn.nukkit.entity.mob.EntityHask; import cn.nukkit.entity.mob.EntityMagmaCube; import cn.nukkit.entity.mob.EntityShulker; import cn.nukkit.entity.mob.EntitySilverfish; import cn.nukkit.entity.mob.EntitySkeleton; import cn.nukkit.entity.mob.EntitySlime; import cn.nukkit.entity.mob.EntitySpider; import cn.nukkit.entity.mob.EntityStray; import cn.nukkit.entity.mob.EntityWitch; import cn.nukkit.entity.mob.EntityWitherSkeleton; import cn.nukkit.entity.mob.EntityZombie; import cn.nukkit.entity.mob.EntityZombiePigman; import cn.nukkit.entity.mob.EntityZombieVillager; import cn.nukkit.entity.passive.EntityBat; import cn.nukkit.entity.passive.EntityChicken; import cn.nukkit.entity.passive.EntityCow; import cn.nukkit.entity.passive.EntityDonkey; import cn.nukkit.entity.passive.EntityHorse; import cn.nukkit.entity.passive.EntityMooshroom; import cn.nukkit.entity.passive.EntityMule; import cn.nukkit.entity.passive.EntityOcelot; import cn.nukkit.entity.passive.EntityPig; import cn.nukkit.entity.passive.EntityPolarBear; import cn.nukkit.entity.passive.EntityRabbit; import cn.nukkit.entity.passive.EntitySheep; import cn.nukkit.entity.passive.EntitySkeletonHorse; import cn.nukkit.entity.passive.EntitySquid; import cn.nukkit.entity.passive.EntityVillager; import cn.nukkit.entity.passive.EntityWolf; import cn.nukkit.entity.passive.EntityZombieHorse; import cn.nukkit.entity.projectile.EntityArrow; import cn.nukkit.entity.projectile.EntityEnderPearl; import cn.nukkit.entity.projectile.EntityFishingHook; import cn.nukkit.entity.projectile.EntitySnowball; import cn.nukkit.entity.weather.EntityLightning; import cn.nukkit.event.HandlerList; import cn.nukkit.event.level.LevelInitEvent; import cn.nukkit.event.level.LevelLoadEvent; import cn.nukkit.event.server.QueryRegenerateEvent; import cn.nukkit.inventory.CraftingManager; import cn.nukkit.inventory.FurnaceRecipe; import cn.nukkit.inventory.Recipe; import cn.nukkit.inventory.ShapedRecipe; import cn.nukkit.inventory.ShapelessRecipe; import cn.nukkit.item.Item; import cn.nukkit.item.enchantment.Enchantment; import cn.nukkit.lang.BaseLang; import cn.nukkit.lang.TextContainer; import cn.nukkit.lang.TranslationContainer; import cn.nukkit.level.Level; import cn.nukkit.level.Position; import cn.nukkit.level.format.LevelProvider; import cn.nukkit.level.format.LevelProviderManager; import cn.nukkit.level.format.anvil.Anvil; import cn.nukkit.level.format.leveldb.LevelDB; import cn.nukkit.level.format.mcregion.McRegion; import cn.nukkit.level.generator.Flat; import cn.nukkit.level.generator.Generator; import cn.nukkit.level.generator.Nether; import cn.nukkit.level.generator.Normal; import cn.nukkit.level.generator.biome.Biome; import cn.nukkit.math.NukkitMath; import cn.nukkit.metadata.EntityMetadataStore; import cn.nukkit.metadata.LevelMetadataStore; import cn.nukkit.metadata.PlayerMetadataStore; import cn.nukkit.nbt.NBTIO; import cn.nukkit.nbt.tag.CompoundTag; import cn.nukkit.nbt.tag.DoubleTag; import cn.nukkit.nbt.tag.FloatTag; import cn.nukkit.nbt.tag.ListTag; import cn.nukkit.network.CompressBatchedTask; import cn.nukkit.network.Network; import cn.nukkit.network.RakNetInterface; import cn.nukkit.network.SourceInterface; import cn.nukkit.network.protocol.BatchPacket; import cn.nukkit.network.protocol.CraftingDataPacket; import cn.nukkit.network.protocol.DataPacket; import cn.nukkit.network.protocol.PlayerListPacket; import cn.nukkit.network.protocol.ProtocolInfo; import cn.nukkit.network.query.QueryHandler; import cn.nukkit.network.rcon.RCON; import cn.nukkit.permission.BanEntry; import cn.nukkit.permission.BanList; import cn.nukkit.permission.DefaultPermissions; import cn.nukkit.permission.Permissible; import cn.nukkit.plugin.JavaPluginLoader; import cn.nukkit.plugin.Plugin; import cn.nukkit.plugin.PluginCompiler; import cn.nukkit.plugin.PluginLoadOrder; import cn.nukkit.plugin.PluginManager; import cn.nukkit.plugin.service.NKServiceManager; import cn.nukkit.plugin.service.ServiceManager; import cn.nukkit.potion.Effect; import cn.nukkit.potion.Potion; import cn.nukkit.resourcepacks.ResourcePackManager; import cn.nukkit.scheduler.FileWriteTask; import cn.nukkit.scheduler.ServerScheduler; import cn.nukkit.utils.Binary; import cn.nukkit.utils.Config; import cn.nukkit.utils.ConfigSection; import cn.nukkit.utils.LevelException; import cn.nukkit.utils.MainLogger; import cn.nukkit.utils.ServerException; import cn.nukkit.utils.ServerKiller; import cn.nukkit.utils.TextFormat; import cn.nukkit.utils.Utils; import cn.nukkit.utils.Zlib; import co.aikar.timings.Timings; /** * @author MagicDroidX * @author Box */ public class Server { public static final String BROADCAST_CHANNEL_ADMINISTRATIVE = "nukkit.broadcast.admin"; public static final String BROADCAST_CHANNEL_USERS = "nukkit.broadcast.user"; private static Server instance = null; private BanList banByName = null; private BanList banByIP = null; private Config operators = null; private Config whitelist = null; private boolean isRunning = true; private boolean hasStopped = false; private PluginManager pluginManager = null; private int profilingTickrate = 20; private ServerScheduler scheduler = null; private int tickCounter; private long nextTick; private final float[] tickAverage = { 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20 }; private final float[] useAverage = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; private float maxTick = 20; private float maxUse = 0; private int sendUsageTicker = 0; private boolean dispatchSignals = false; private final MainLogger logger; private final CommandReader console; private SimpleCommandMap commandMap; private CraftingManager craftingManager; private ResourcePackManager resourcePackManager; private ConsoleCommandSender consoleSender; private int maxPlayers; private boolean autoSave; private RCON rcon; private EntityMetadataStore entityMetadata; private PlayerMetadataStore playerMetadata; private LevelMetadataStore levelMetadata; private Network network; private boolean networkCompressionAsync = true; public int networkCompressionLevel = 7; private boolean autoTickRate = true; private int autoTickRateLimit = 20; private boolean alwaysTickPlayers = false; private int baseTickRate = 1; private Boolean getAllowFlight = null; private int autoSaveTicker = 0; private int autoSaveTicks = 6000; private BaseLang baseLang; private boolean forceLanguage = false; private UUID serverID; private final String filePath; private final String dataPath; private final String pluginPath; private String defaultplugin = null; private final Set<UUID> uniquePlayers = new HashSet<>(); private QueryHandler queryHandler; private QueryRegenerateEvent queryRegenerateEvent; private Config properties; private Config config; private final Map<String, Player> players = new HashMap<>(); private final Map<UUID, Player> playerList = new HashMap<>(); private final Map<Integer, String> identifier = new HashMap<>(); private final Map<Integer, Level> levels = new HashMap<>(); private final ServiceManager serviceManager = new NKServiceManager(); private Level defaultLevel = null; private Thread currentThread; private Map<String, Object> jupiterconfig; @SuppressWarnings("unchecked") Server(MainLogger logger, final String filePath, String dataPath, String pluginPath) { Preconditions.checkState(instance == null, "Already initialized!"); currentThread = Thread.currentThread(); // Saves the current thread instance as a reference, used in Server#isPrimaryThread() instance = this; this.logger = logger; this.filePath = filePath; if (!new File(dataPath + "worlds/").exists()) { new File(dataPath + "worlds/").mkdirs(); this.getLogger().info(TextFormat.AQUA + dataPath + "worlds/ was created!"); } if (!new File(dataPath + "players/").exists()) { new File(dataPath + "players/").mkdirs(); this.getLogger().info(TextFormat.AQUA + dataPath + "players/ was created!"); } if (!new File(pluginPath).exists()) { new File(pluginPath).mkdirs(); this.getLogger().info(TextFormat.AQUA + pluginPath + "plugins/ was created!"); this.getLogger().info(TextFormat.AQUA + dataPath + "worlds/ ?????"); } if (!new File(dataPath + "players/").exists()) { new File(dataPath + "players/").mkdirs(); this.getLogger().info(TextFormat.AQUA + dataPath + "players/ ?????"); } if (!new File(pluginPath).exists()) { new File(pluginPath).mkdirs(); this.getLogger().info(TextFormat.AQUA + pluginPath + " ?????"); } if (!new File(dataPath + "unpackedPlugins/").exists()) { new File(dataPath + "unpackedPlugins/").mkdirs(); this.getLogger().info(TextFormat.AQUA + pluginPath + "unpackedPlugins/ ?????"); } if (!new File(dataPath + "compileOrder/").exists()) { new File(dataPath + "compileOrder/").mkdirs(); this.getLogger().info(TextFormat.AQUA + pluginPath + "compileOrder/ ?????"); } this.dataPath = new File(dataPath).getAbsolutePath() + "/"; this.pluginPath = new File(pluginPath).getAbsolutePath() + "/"; this.console = new CommandReader(); //todo: VersionString ?? if (!new File(this.dataPath + "nukkit.yml").exists()) { this.getLogger().info(TextFormat.GREEN + "Welcome! Please choose a language first!"); try { String[] lines = Utils .readFile(this.getClass().getClassLoader().getResourceAsStream("lang/language.list")) .split("\n"); for (String line : lines) { this.getLogger().info(line); } } catch (IOException e) { throw new RuntimeException(e); } String fallback = BaseLang.FALLBACK_LANGUAGE; String language = null; while (language == null) { String lang = this.console.readLine(); InputStream conf = this.getClass().getClassLoader() .getResourceAsStream("lang/" + lang + "/lang.ini"); if (conf != null) { language = lang; } } InputStream advacedConf = this.getClass().getClassLoader() .getResourceAsStream("lang/" + language + "/nukkit.yml"); if (advacedConf == null) { advacedConf = this.getClass().getClassLoader() .getResourceAsStream("lang/" + fallback + "/nukkit.yml"); } try { Utils.writeFile(this.dataPath + "nukkit.yml", advacedConf); } catch (IOException e) { throw new RuntimeException(e); } } this.console.start(); this.logger.info(TextFormat.GREEN + "nukkit.yml" + TextFormat.WHITE + "?????..."); this.config = new Config(this.dataPath + "nukkit.yml", Config.YAML); this.logger .info(TextFormat.GREEN + "server.properties" + TextFormat.WHITE + "?????..."); this.properties = new Config(this.dataPath + "server.properties", Config.PROPERTIES, new ConfigSection() { { put("motd", "Jupiter Server For Minecraft: PE"); put("server-port", 19132); put("server-ip", "0.0.0.0"); put("view-distance", 10); put("white-list", false); put("achievements", true); put("announce-player-achievements", true); put("spawn-protection", 16); put("max-players", 20); put("allow-flight", false); put("spawn-animals", true); put("spawn-mobs", true); put("gamemode", 0); put("force-gamemode", false); put("hardcore", false); put("pvp", true); put("difficulty", 1); put("generator-settings", ""); put("level-name", "world"); put("level-seed", ""); put("level-type", "DEFAULT"); put("enable-query", true); put("enable-rcon", false); put("rcon.password", Base64.getEncoder() .encodeToString(UUID.randomUUID().toString().replace("-", "").getBytes()).substring(3, 13)); put("auto-save", true); put("force-resources", false); } }); this.logger.info(TextFormat.GREEN + "jupiter.yml" + TextFormat.WHITE + "?????..."); if (!new File(this.dataPath + "jupiter.yml").exists()) { InputStream advacedConf = this.getClass().getClassLoader().getResourceAsStream("lang/jpn/jupiter.yml"); if (advacedConf == null) this.getLogger().error( "Jupiter.yml????????????????"); try { Utils.writeFile(this.dataPath + "jupiter.yml", advacedConf); } catch (IOException e) { throw new RuntimeException(e); } } this.loadJupiterConfig(); InputStream advacedConf1 = this.getClass().getClassLoader().getResourceAsStream("lang/jpn/jupiter.yml"); if (advacedConf1 == null) this.getLogger().error( "Jupiter.yml????????????????"); try { Utils.writeFile(this.dataPath + "jupiter1.yml", advacedConf1); } catch (IOException e) { throw new RuntimeException(e); } //get Jupiter.yml in the jar Config jupiter = new Config(this.getDataPath() + "jupiter1.yml"); Map<String, Object> jmap = jupiter.getAll(); Collection<Object> objj = jmap.values(); Object[] objj1 = objj.toArray(); Object objj2 = objj1[objj1.length - 1]; BidiMap mapp = new DualHashBidiMap(jmap); String keyy = (String) mapp.getKey(objj2); //get JupiterConfig key in the delectory Collection<Object> obj = jupiterconfig.values(); Object[] obj1 = obj.toArray(); Object obj2 = obj1[obj1.length - 1]; BidiMap map = new DualHashBidiMap(jupiterconfig); String key1 = (String) map.getKey(obj2); //delete jupiter1.yml File jf = new File(this.dataPath + "jupiter1.yml"); jf.delete(); if (!keyy.equals(key1)) { File conf = new File(this.dataPath + "jupiter.yml"); conf.delete(); InputStream advacedConf = this.getClass().getClassLoader().getResourceAsStream("lang/jpn/jupiter.yml"); if (advacedConf == null) this.getLogger().error( "Jupiter.yml????????????????"); try { Utils.writeFile(this.dataPath + "jupiter.yml", advacedConf); } catch (IOException ex) { throw new RuntimeException(ex); } this.getLogger() .info(TextFormat.AQUA + "Jupiter.yml????????????"); this.loadJupiterConfig(); } if (this.getJupiterConfigBoolean("destroy-block-particle")) { Level.sendDestroyParticle = true; } else { Level.sendDestroyParticle = false; } this.forceLanguage = (Boolean) this.getConfig("settings.force-language", false); this.baseLang = new BaseLang((String) this.getConfig("settings.language", BaseLang.FALLBACK_LANGUAGE)); this.logger.info(this.getLanguage().translateString("language.selected", new String[] { getLanguage().getName(), getLanguage().getLang() })); this.logger.info(this.getLanguage().translateString("nukkit.server.start", TextFormat.AQUA + this.getVersion() + TextFormat.WHITE)); Object poolSize = this.getConfig("settings.async-workers", "auto"); if (!(poolSize instanceof Integer)) { try { poolSize = Integer.valueOf((String) poolSize); } catch (Exception e) { poolSize = Math.max(Runtime.getRuntime().availableProcessors() + 1, 4); } } ServerScheduler.WORKERS = (int) poolSize; int threshold; try { threshold = Integer.valueOf(String.valueOf(this.getConfig("network.batch-threshold", 256))); } catch (Exception e) { threshold = 256; } if (threshold < 0) { threshold = -1; } Network.BATCH_THRESHOLD = threshold; this.networkCompressionLevel = (int) this.getConfig("network.compression-level", 7); this.networkCompressionAsync = (boolean) this.getConfig("network.async-compression", true); this.networkCompressionLevel = (int) this.getConfig("network.compression-level", 7); this.networkCompressionAsync = (boolean) this.getConfig("network.async-compression", true); this.autoTickRate = (boolean) this.getConfig("level-settings.auto-tick-rate", true); this.autoTickRateLimit = (int) this.getConfig("level-settings.auto-tick-rate-limit", 20); this.alwaysTickPlayers = (boolean) this.getConfig("level-settings.always-tick-players", false); this.baseTickRate = (int) this.getConfig("level-settings.base-tick-rate", 1); this.scheduler = new ServerScheduler(); if (this.getPropertyBoolean("enable-rcon", false)) { this.rcon = new RCON(this, this.getPropertyString("rcon.password", ""), (!this.getIp().equals("")) ? this.getIp() : "0.0.0.0", this.getPropertyInt("rcon.port", this.getPort())); } this.entityMetadata = new EntityMetadataStore(); this.playerMetadata = new PlayerMetadataStore(); this.levelMetadata = new LevelMetadataStore(); this.operators = new Config(this.dataPath + "ops.txt", Config.ENUM); this.whitelist = new Config(this.dataPath + "white-list.txt", Config.ENUM); this.banByName = new BanList(this.dataPath + "banned-players.json"); this.banByName.load(); this.banByIP = new BanList(this.dataPath + "banned-ips.json"); this.banByIP.load(); this.maxPlayers = this.getPropertyInt("max-players", 20); this.setAutoSave(this.getPropertyBoolean("auto-save", true)); if (this.getPropertyBoolean("hardcore", false) && this.getDifficulty() < 3) { this.setPropertyInt("difficulty", 3); } Nukkit.DEBUG = (int) this.getConfig("debug.level", 1); if (this.logger instanceof MainLogger) { this.logger.setLogDebug(Nukkit.DEBUG > 1); } this.logger.info(this.getLanguage().translateString("nukkit.server.networkStart", new String[] { this.getIp().equals("") ? "*" : this.getIp(), String.valueOf(this.getPort()) })); this.serverID = UUID.randomUUID(); this.network = new Network(this); this.network.setName(this.getMotd()); this.logger.info(this.getLanguage().translateString("nukkit.server.info", this.getName(), TextFormat.YELLOW + this.getNukkitVersion() + TextFormat.WHITE, TextFormat.AQUA + this.getCodename() + TextFormat.WHITE, this.getApiVersion())); this.logger.info(this.getLanguage().translateString("nukkit.server.license", this.getName())); this.consoleSender = new ConsoleCommandSender(); this.commandMap = new SimpleCommandMap(this); this.registerEntities(); this.registerBlockEntities(); Block.init(); Enchantment.init(); Item.init(); Biome.init(); Effect.init(); Potion.init(); Attribute.init(); this.craftingManager = new CraftingManager(); this.resourcePackManager = new ResourcePackManager(new File(Nukkit.DATA_PATH, "resource_packs")); this.pluginManager = new PluginManager(this, this.commandMap); this.pluginManager.subscribeToPermission(Server.BROADCAST_CHANNEL_ADMINISTRATIVE, this.consoleSender); this.pluginManager.registerInterface(JavaPluginLoader.class); this.queryRegenerateEvent = new QueryRegenerateEvent(this, 5); this.network.registerInterface(new RakNetInterface(this)); Calendar now = Calendar.getInstance(); int y = now.get(Calendar.YEAR); int mo = now.get(Calendar.MONTH) + 1; int d = now.get(Calendar.DATE); int h = now.get(Calendar.HOUR_OF_DAY); int m = now.get(Calendar.MINUTE); int s = now.get(Calendar.SECOND); this.logger.info(TextFormat.AQUA + "=================================================================================="); this.logger.info(TextFormat.AQUA + ""); this.logger.info( " || || || || || || || ||"); this.logger.info(" | | | | | | | || | | | | | | | | || |"); this.logger.info(" | | | | | | | | | | | | | | | | "); this.logger.info(" _| | | | | | | | | | | | | | | | "); this.logger.info(" |____| |_____| |_| |__| |__| | | |_| _|"); this.logger.info(""); this.logger.info(TextFormat.AQUA + ""); this.logger.info(TextFormat.AQUA + "----------------------------------------------------------------------------------"); this.logger.info(TextFormat.GREEN + "Jupiter - Nukkit Fork"); this.logger.info(TextFormat.YELLOW + "JupiterDevelopmentTeam "); this.logger.info(TextFormat.AQUA + "----------------------------------------------------------------------------------"); this.logger.info( ": " + TextFormat.BLUE + y + "/" + mo + "/" + d + " " + h + "" + m + "" + s + ""); this.logger.info("???: " + TextFormat.GREEN + this.getMotd()); this.logger.info("ip: " + TextFormat.GREEN + this.getIp()); this.logger.info("?: " + TextFormat.GREEN + this.getPort()); this.logger.info("Nukkit?: " + TextFormat.LIGHT_PURPLE + this.getNukkitVersion()); this.logger.info("API?: " + TextFormat.LIGHT_PURPLE + this.getApiVersion()); this.logger.info("?: " + TextFormat.LIGHT_PURPLE + this.getCodename()); this.logger.info(TextFormat.AQUA + "=================================================================================="); if (this.getJupiterConfigBoolean("jupiter-compiler-mode")) { this.logger.info(TextFormat.YELLOW + "----------------------------------------------------------------------------------"); getLogger().info(TextFormat.AQUA + "?????..."); File f = new File(dataPath + "compileOrder/"); File[] list = f.listFiles(); for (int i = 0; i < list.length; i++) { if (new PluginCompiler().Compile(list[i])) getLogger().info(list[i].toPath().toString() + " :" + TextFormat.GREEN + ""); else getLogger().info(list[i].toPath().toString() + " :" + TextFormat.RED + ""); } this.logger.info(TextFormat.YELLOW + "----------------------------------------------------------------------------------"); } this.logger.info(TextFormat.LIGHT_PURPLE + "----------------------------------------------------------------------------------"); getLogger().info(TextFormat.AQUA + "?????..."); this.pluginManager.loadPlugins(this.pluginPath); this.enablePlugins(PluginLoadOrder.STARTUP); LevelProviderManager.addProvider(this, Anvil.class); LevelProviderManager.addProvider(this, McRegion.class); LevelProviderManager.addProvider(this, LevelDB.class); Generator.addGenerator(Flat.class, "flat", Generator.TYPE_FLAT); Generator.addGenerator(Normal.class, "normal", Generator.TYPE_INFINITE); Generator.addGenerator(Normal.class, "default", Generator.TYPE_INFINITE); Generator.addGenerator(Nether.class, "nether", Generator.TYPE_NETHER); //todo: add old generator and hell generator for (String name : ((Map<String, Object>) this.getConfig("worlds", new HashMap<>())).keySet()) { if (!this.loadLevel(name)) { long seed; try { seed = ((Integer) this.getConfig("worlds." + name + ".seed")).longValue(); } catch (Exception e) { seed = System.currentTimeMillis(); } Map<String, Object> options = new HashMap<>(); String[] opts = ((String) this.getConfig("worlds." + name + ".generator", Generator.getGenerator("default").getSimpleName())).split(":"); Class<? extends Generator> generator = Generator.getGenerator(opts[0]); if (opts.length > 1) { String preset = ""; for (int i = 1; i < opts.length; i++) { preset += opts[i] + ":"; } preset = preset.substring(0, preset.length() - 1); options.put("preset", preset); } this.generateLevel(name, seed, generator, options); } } if (this.getDefaultLevel() == null) { String defaultName = this.getPropertyString("level-name", "world"); if (defaultName == null || "".equals(defaultName.trim())) { this.getLogger().warning("level-name cannot be null, using default"); defaultName = "world"; this.setPropertyString("level-name", defaultName); } if (!this.loadLevel(defaultName)) { long seed; String seedString = String.valueOf(this.getProperty("level-seed", System.currentTimeMillis())); try { seed = Long.valueOf(seedString); } catch (NumberFormatException e) { seed = seedString.hashCode(); } this.generateLevel(defaultName, seed == 0 ? System.currentTimeMillis() : seed); } this.setDefaultLevel(this.getLevelByName(defaultName)); } this.properties.save(true); if (this.getDefaultLevel() == null) { this.getLogger().emergency(this.getLanguage().translateString("nukkit.level.defaultError")); this.forceShutdown(); return; } if ((int) this.getConfig("ticks-per.autosave", 6000) > 0) { this.autoSaveTicks = (int) this.getConfig("ticks-per.autosave", 6000); } this.enablePlugins(PluginLoadOrder.POSTWORLD); this.logger.info(TextFormat.LIGHT_PURPLE + "----------------------------------------------------------------------------------"); this.start(); } /** * ??????? * <br>????? * (...isMuted()?) * @see "?????" * @see Player#sendImportantMessage(String) sendImportantMessage * @see Player#isMuted() isMuted() * @param message ? * @return int */ public int broadcastMessage(String message) { return this.broadcast(message, BROADCAST_CHANNEL_USERS); } /** * ??????? * <br>????? * (...isMuted()?) * @see "?????" * @see Player#sendImportantMessage(String) sendImportantMessage * @see Player#isMuted() isMuted() * @param message ? * @return int */ public int broadcastMessage(TextContainer message) { return this.broadcast(message, BROADCAST_CHANNEL_USERS); } public int broadcastMessage(String message, CommandSender[] recipients) { for (CommandSender recipient : recipients) { recipient.sendMessage(message); } return recipients.length; } public int broadcastMessage(String message, Collection<CommandSender> recipients) { for (CommandSender recipient : recipients) { recipient.sendMessage(message); } return recipients.size(); } public int broadcastMessage(TextContainer message, Collection<CommandSender> recipients) { for (CommandSender recipient : recipients) { recipient.sendMessage(message); } return recipients.size(); } /** * ???????? * <br>????? * (...isMuted()?) * @param message ? * @return int */ public int broadcastPopup(String message) { return this.broadcastPopup(message, BROADCAST_CHANNEL_USERS); } /** * ???????? * <br>????? * @param message ? * @return int */ public int broadcastTip(String message) { return this.broadcastPopup(message, BROADCAST_CHANNEL_USERS); } /** * ??????? * <br>????? * @param message ? * @return int */ public int broadcastTitle(String message) { return this.broadcastTitle(message, BROADCAST_CHANNEL_USERS); } /** * ??????? * <br>????? * @param message ? * @return int */ public int broadcastSubtitle(String message) { return this.broadcastSubtitle(message, BROADCAST_CHANNEL_USERS); } /** * ??????? * <br>???? * (...isMuted()?) * @see Player#isMuted() isMuted() * @param message ? * @return int * @author Itsu */ public int broadcastImportantMessage(String message) { return this.broadcastImportantMessage(message, BROADCAST_CHANNEL_USERS); } public int broadcast(String message, String permissions) { Set<CommandSender> recipients = new HashSet<>(); for (String permission : permissions.split(";")) { for (Permissible permissible : this.pluginManager.getPermissionSubscriptions(permission)) { if (permissible instanceof CommandSender && permissible.hasPermission(permission)) { recipients.add((CommandSender) permissible); } } } for (CommandSender recipient : recipients) { recipient.sendMessage(message); } return recipients.size(); } public int broadcast(TextContainer message, String permissions) { Set<CommandSender> recipients = new HashSet<>(); for (String permission : permissions.split(";")) { for (Permissible permissible : this.pluginManager.getPermissionSubscriptions(permission)) { if (permissible instanceof CommandSender && permissible.hasPermission(permission)) { recipients.add((CommandSender) permissible); } } } for (CommandSender recipient : recipients) { recipient.sendMessage(message); } return recipients.size(); } public int broadcastPopup(String message, String permissions) { Set<Player> recipients = new HashSet<>(); for (String permission : permissions.split(";")) { for (Permissible permissible : this.pluginManager.getPermissionSubscriptions(permission)) { if (permissible instanceof Player && permissible.hasPermission(permission)) { recipients.add((Player) permissible); } } } for (Player recipient : recipients) { recipient.sendPopup(message); } return recipients.size(); } public int broadcastTip(String message, String permissions) { Set<Player> recipients = new HashSet<>(); for (String permission : permissions.split(";")) { for (Permissible permissible : this.pluginManager.getPermissionSubscriptions(permission)) { if (permissible instanceof Player && permissible.hasPermission(permission)) { recipients.add((Player) permissible); } } } for (Player recipient : recipients) { recipient.sendTip(message); } return recipients.size(); } public int broadcastTitle(String message, String permissions) { Set<Player> recipients = new HashSet<>(); for (String permission : permissions.split(";")) { for (Permissible permissible : this.pluginManager.getPermissionSubscriptions(permission)) { if (permissible instanceof Player && permissible.hasPermission(permission)) { recipients.add((Player) permissible); } } } for (Player recipient : recipients) { recipient.sendTitle(message); } return recipients.size(); } public int broadcastSubtitle(String message, String permissions) { Set<Player> recipients = new HashSet<>(); for (String permission : permissions.split(";")) { for (Permissible permissible : this.pluginManager.getPermissionSubscriptions(permission)) { if (permissible instanceof Player && permissible.hasPermission(permission)) { recipients.add((Player) permissible); } } } for (Player recipient : recipients) { recipient.setSubtitle(message); } return recipients.size(); } public int broadcastImportantMessage(String message, String permissions) { Set<CommandSender> recipients = new HashSet<>(); for (String permission : permissions.split(";")) { for (Permissible permissible : this.pluginManager.getPermissionSubscriptions(permission)) { if (permissible instanceof CommandSender && permissible.hasPermission(permission)) { recipients.add((CommandSender) permissible); } } } for (CommandSender recipient : recipients) { recipient.sendImportantMessage(message); } return recipients.size(); } /** * ??????? * @param players * @param packet ? * @return void */ public static void broadcastPacket(Collection<Player> players, DataPacket packet) { broadcastPacket(players.stream().toArray(Player[]::new), packet); } /** * ??????? * @param players * @param packet ? * @return void */ public static void broadcastPacket(Player[] players, DataPacket packet) { packet.encode(); packet.isEncoded = true; if (Network.BATCH_THRESHOLD >= 0 && packet.getBuffer().length >= Network.BATCH_THRESHOLD) { Server.getInstance().batchPackets(players, new DataPacket[] { packet }, false); return; } for (Player player : players) { player.dataPacket(packet); } if (packet.encapsulatedPacket != null) { packet.encapsulatedPacket = null; } } public void batchPackets(Player[] players, DataPacket[] packets) { this.batchPackets(players, packets, false); } public void batchPackets(Player[] players, DataPacket[] packets, boolean forceSync) { if (players == null || packets == null || players.length == 0 || packets.length == 0) { return; } Timings.playerNetworkSendTimer.startTiming(); byte[][] payload = new byte[packets.length * 2][]; for (int i = 0; i < packets.length; i++) { DataPacket p = packets[i]; if (!p.isEncoded) { p.encode(); } byte[] buf = p.getBuffer(); payload[i * 2] = Binary.writeUnsignedVarInt(buf.length); payload[i * 2 + 1] = buf; } byte[] data; data = Binary.appendBytes(payload); List<String> targets = new ArrayList<>(); for (Player p : players) { if (p.isConnected()) { targets.add(this.identifier.get(p.rawHashCode())); } } if (!forceSync && this.networkCompressionAsync) { this.getScheduler() .scheduleAsyncTask(new CompressBatchedTask(data, targets, this.networkCompressionLevel)); } else { try { this.broadcastPacketsCallback(Zlib.deflate(data, this.networkCompressionLevel), targets); } catch (Exception e) { throw new RuntimeException(e); } } Timings.playerNetworkSendTimer.stopTiming(); } public void broadcastPacketsCallback(byte[] data, List<String> identifiers) { BatchPacket pk = new BatchPacket(); pk.payload = data; pk.encode(); pk.isEncoded = true; for (String i : identifiers) { if (this.players.containsKey(i)) { this.players.get(i).dataPacket(pk); } } } public void enablePlugins(PluginLoadOrder type) { for (Plugin plugin : new ArrayList<>(this.pluginManager.getPlugins().values())) { if (!plugin.isEnabled() && type == plugin.getDescription().getOrder()) { this.enablePlugin(plugin); } } if (type == PluginLoadOrder.POSTWORLD) { this.commandMap.registerServerAliases(); DefaultPermissions.registerCorePermissions(); } } public void enablePlugin(Plugin plugin) { this.pluginManager.enablePlugin(plugin); } public void disablePlugins() { this.pluginManager.disablePlugins(); } /** * ??? * @param sender ?CommandSender * @param commandLine ? * @return boolean true?/false? */ public boolean dispatchCommand(CommandSender sender, String commandLine) throws ServerException { // First we need to check if this command is on the main thread or not, if not, warn the user if (!this.isPrimaryThread()) { getLogger().warning("Command Dispatched Async: " + commandLine); getLogger().warning("Please notify author of plugin causing this execution to fix this bug!", new Throwable()); // TODO: We should sync the command to the main thread too! } if (sender == null) { throw new ServerException("CommandSender is not valid"); } if (this.commandMap.dispatch(sender, commandLine)) { return true; } sender.sendMessage(new TranslationContainer(TextFormat.RED + "%commands.generic.notFound")); return false; } //todo: use ticker to check console public ConsoleCommandSender getConsoleSender() { return consoleSender; } /** * ???????? * @return void */ public void reload() { this.logger.info("???..."); this.logger.info("??????..."); for (Level level : this.levels.values()) { level.save(); } this.pluginManager.disablePlugins(); this.pluginManager.clearPlugins(); this.commandMap.clearCommands(); this.logger.info("server.properties????????..."); this.properties.reload(); this.maxPlayers = this.getPropertyInt("max-players", 20); if (this.getPropertyBoolean("hardcore", false) && this.getDifficulty() < 3) { this.setPropertyInt("difficulty", 3); } this.banByIP.load(); this.banByName.load(); this.reloadWhitelist(); this.operators.reload(); for (BanEntry entry : this.getIPBans().getEntires().values()) { this.getNetwork().blockAddress(entry.getName(), -1); } this.pluginManager.registerInterface(JavaPluginLoader.class); this.pluginManager.loadPlugins(this.pluginPath); this.enablePlugins(PluginLoadOrder.STARTUP); this.enablePlugins(PluginLoadOrder.POSTWORLD); Timings.reset(); } /** * ????? * @return void */ public void shutdown() { if (this.isRunning) { ServerKiller killer = new ServerKiller(90); killer.start(); } this.isRunning = false; } public void forceShutdown() { if (this.hasStopped) { return; } try { if (!this.isRunning) { //todo sendUsage } // clean shutdown of console thread asap this.console.shutdown(); this.hasStopped = true; this.shutdown(); if (this.rcon != null) { this.rcon.close(); } this.getLogger().debug("Disabling all plugins"); this.pluginManager.disablePlugins(); for (Player player : new ArrayList<>(this.players.values())) { player.close(player.getLeaveMessage(), (String) this.getConfig("settings.shutdown-message", "Server closed")); } this.getLogger().debug("Unloading all levels"); for (Level level : new ArrayList<>(this.getLevels().values())) { this.unloadLevel(level, true); } this.getLogger().debug("Removing event handlers"); HandlerList.unregisterAll(); this.getLogger().debug("Stopping all tasks"); this.scheduler.cancelAllTasks(); this.scheduler.mainThreadHeartbeat(Integer.MAX_VALUE); this.getLogger().debug("Closing console"); this.console.interrupt(); this.getLogger().debug("Stopping network interfaces"); for (SourceInterface interfaz : this.network.getInterfaces()) { interfaz.shutdown(); this.network.unregisterInterface(interfaz); } this.getLogger().debug("Disabling timings"); Timings.stopServer(); //todo other things } catch (Exception e) { this.logger.logException(e); //todo remove this? this.logger.emergency("Exception happened while shutting down, exit the process"); System.exit(1); } } /** * ????? * @return void */ public void start() { if (this.getPropertyBoolean("enable-query", true)) { this.queryHandler = new QueryHandler(); } for (BanEntry entry : this.getIPBans().getEntires().values()) { this.network.blockAddress(entry.getName(), -1); } //todo send usage setting this.tickCounter = 0; this.logger.info(this.getLanguage().translateString("nukkit.server.defaultGameMode", getGamemodeString(this.getGamemode()))); this.logger.info(this.getLanguage().translateString("nukkit.server.startFinished", String.valueOf((double) (System.currentTimeMillis() - Nukkit.START_TIME) / 1000))); this.tickProcessor(); this.forceShutdown(); } public void handlePacket(String address, int port, byte[] payload) { try { if (payload.length > 2 && Arrays.equals(Binary.subBytes(payload, 0, 2), new byte[] { (byte) 0xfe, (byte) 0xfd }) && this.queryHandler != null) { this.queryHandler.handle(address, port, payload); } } catch (Exception e) { this.logger.logException(e); this.getNetwork().blockAddress(address, 600); } } public void tickProcessor() { this.nextTick = System.currentTimeMillis(); try { while (this.isRunning) { try { this.tick(); long next = this.nextTick; long current = System.currentTimeMillis(); if (next - 0.1 > current) { Thread.sleep(next - current - 1, 900000); } } catch (RuntimeException e) { this.getLogger().logException(e); } } } catch (Throwable e) { this.logger.emergency("Exception happened while ticking server"); this.logger.alert(Utils.getExceptionMessage(e)); this.logger.alert(Utils.getAllThreadDumps()); } } public void onPlayerLogin(Player player) { if (this.sendUsageTicker > 0) { this.uniquePlayers.add(player.getUniqueId()); } } public void addPlayer(String identifier, Player player) { this.players.put(identifier, player); this.identifier.put(player.rawHashCode(), identifier); } public void addOnlinePlayer(Player player) { this.playerList.put(player.getUniqueId(), player); this.updatePlayerListData(player.getUniqueId(), player.getId(), player.getDisplayName(), player.getSkin()); } public void removeOnlinePlayer(Player player) { if (this.playerList.containsKey(player.getUniqueId())) { this.playerList.remove(player.getUniqueId()); PlayerListPacket pk = new PlayerListPacket(); pk.type = PlayerListPacket.TYPE_REMOVE; pk.entries = new PlayerListPacket.Entry[] { new PlayerListPacket.Entry(player.getUniqueId()) }; Server.broadcastPacket(this.playerList.values(), pk); } } public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin) { this.updatePlayerListData(uuid, entityId, name, skin, this.playerList.values()); } public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin, Player[] players) { PlayerListPacket pk = new PlayerListPacket(); pk.type = PlayerListPacket.TYPE_ADD; pk.entries = new PlayerListPacket.Entry[] { new PlayerListPacket.Entry(uuid, entityId, name, skin) }; Server.broadcastPacket(players, pk); } public void updatePlayerListData(UUID uuid, long entityId, String name, Skin skin, Collection<Player> players) { this.updatePlayerListData(uuid, entityId, name, skin, players.stream().filter(p -> !p.getUniqueId().equals(uuid)).toArray(Player[]::new)); } public void removePlayerListData(UUID uuid) { this.removePlayerListData(uuid, this.playerList.values()); } public void removePlayerListData(UUID uuid, Player[] players) { PlayerListPacket pk = new PlayerListPacket(); pk.type = PlayerListPacket.TYPE_REMOVE; pk.entries = new PlayerListPacket.Entry[] { new PlayerListPacket.Entry(uuid) }; Server.broadcastPacket(players, pk); } public void removePlayerListData(UUID uuid, Collection<Player> players) { this.removePlayerListData(uuid, players.stream().toArray(Player[]::new)); } public void sendFullPlayerListData(Player player) { final UUID uuid = player.getUniqueId(); PlayerListPacket pk = new PlayerListPacket(); pk.type = PlayerListPacket.TYPE_ADD; pk.entries = this.playerList.values().stream().filter(p -> !p.getUniqueId().equals(uuid)) .map(p -> new PlayerListPacket.Entry(p.getUniqueId(), p.getId(), p.getDisplayName(), p.getSkin())) .toArray(PlayerListPacket.Entry[]::new); player.dataPacket(pk); } public void sendRecipeList(Player player) { CraftingDataPacket pk = new CraftingDataPacket(); pk.cleanRecipes = true; for (Recipe recipe : this.getCraftingManager().getRecipes().values()) { if (recipe instanceof ShapedRecipe) { pk.addShapedRecipe((ShapedRecipe) recipe); } else if (recipe instanceof ShapelessRecipe) { pk.addShapelessRecipe((ShapelessRecipe) recipe); } } for (FurnaceRecipe recipe : this.getCraftingManager().getFurnaceRecipes().values()) { pk.addFurnaceRecipe(recipe); } player.dataPacket(pk); } private void checkTickUpdates(int currentTick, long tickTime) { for (Player p : new ArrayList<>(this.players.values())) { /*if (!p.loggedIn && (tickTime - p.creationTime) >= 10000 && p.kick(PlayerKickEvent.Reason.LOGIN_TIMEOUT, "Login timeout")) { continue; } client freezes when applying resource packs todo: fix*/ if (this.alwaysTickPlayers) { p.onUpdate(currentTick); } } //Do level ticks for (Level level : this.getLevels().values()) { if (level.getTickRate() > this.baseTickRate && --level.tickRateCounter > 0) { continue; } try { long levelTime = System.currentTimeMillis(); level.doTick(currentTick); int tickMs = (int) (System.currentTimeMillis() - levelTime); level.tickRateTime = tickMs; if (this.autoTickRate) { if (tickMs < 50 && level.getTickRate() > this.baseTickRate) { int r; level.setTickRate(r = level.getTickRate() - 1); if (r > this.baseTickRate) { level.tickRateCounter = level.getTickRate(); } this.getLogger().debug("Raising level \"" + level.getName() + "\" tick rate to " + level.getTickRate() + " ticks"); } else if (tickMs >= 50) { if (level.getTickRate() == this.baseTickRate) { level.setTickRate((int) Math.max(this.baseTickRate + 1, Math.min(this.autoTickRateLimit, Math.floor(tickMs / 50)))); this.getLogger() .debug("Level \"" + level.getName() + "\" took " + NukkitMath.round(tickMs, 2) + "ms, setting tick rate to " + level.getTickRate() + " ticks"); } else if ((tickMs / level.getTickRate()) >= 50 && level.getTickRate() < this.autoTickRateLimit) { level.setTickRate(level.getTickRate() + 1); this.getLogger() .debug("Level \"" + level.getName() + "\" took " + NukkitMath.round(tickMs, 2) + "ms, setting tick rate to " + level.getTickRate() + " ticks"); } level.tickRateCounter = level.getTickRate(); } } } catch (Exception e) { if (Nukkit.DEBUG > 1 && this.logger != null) { this.logger.logException(e); } this.logger.critical(this.getLanguage().translateString("nukkit.level.tickError", new String[] { level.getName(), e.toString() })); this.logger.logException(e); } } } public void doAutoSave() { if (this.getAutoSave()) { Timings.levelSaveTimer.startTiming(); for (Player player : new ArrayList<>(this.players.values())) { if (player.isOnline()) { player.save(true); } else if (!player.isConnected()) { this.removePlayer(player); } } for (Level level : this.getLevels().values()) { level.save(); } Timings.levelSaveTimer.stopTiming(); } } private boolean tick() { long tickTime = System.currentTimeMillis(); long tickTimeNano = System.nanoTime(); if ((tickTime - this.nextTick) < -25) { return false; } Timings.fullServerTickTimer.startTiming(); ++this.tickCounter; Timings.connectionTimer.startTiming(); this.network.processInterfaces(); if (this.rcon != null) { this.rcon.check(); } Timings.connectionTimer.stopTiming(); Timings.schedulerTimer.startTiming(); this.scheduler.mainThreadHeartbeat(this.tickCounter); Timings.schedulerTimer.stopTiming(); this.checkTickUpdates(this.tickCounter, tickTime); for (Player player : new ArrayList<>(this.players.values())) { player.checkNetwork(); } if ((this.tickCounter & 0b1111) == 0) { this.titleTick(); this.maxTick = 20; this.maxUse = 0; if ((this.tickCounter & 0b111111111) == 0) { try { this.getPluginManager() .callEvent(this.queryRegenerateEvent = new QueryRegenerateEvent(this, 5)); if (this.queryHandler != null) { this.queryHandler.regenerateInfo(); } } catch (Exception e) { this.logger.logException(e); } } this.getNetwork().updateName(); } if (this.autoSave && ++this.autoSaveTicker >= this.autoSaveTicks) { this.autoSaveTicker = 0; this.doAutoSave(); } if (this.sendUsageTicker > 0 && --this.sendUsageTicker == 0) { this.sendUsageTicker = 6000; //todo sendUsage } if (this.tickCounter % 100 == 0) { for (Level level : this.levels.values()) { level.clearCache(); level.doChunkGarbageCollection(); } } Timings.fullServerTickTimer.stopTiming(); //long now = System.currentTimeMillis(); long nowNano = System.nanoTime(); //float tick = Math.min(20, 1000 / Math.max(1, now - tickTime)); //float use = Math.min(1, (now - tickTime) / 50); float tick = (float) Math.min(20, 1000000000 / Math.max(1000000, ((double) nowNano - tickTimeNano))); float use = (float) Math.min(1, ((double) (nowNano - tickTimeNano)) / 50000000); if (this.maxTick > tick) { this.maxTick = tick; } if (this.maxUse < use) { this.maxUse = use; } System.arraycopy(this.tickAverage, 1, this.tickAverage, 0, this.tickAverage.length - 1); this.tickAverage[this.tickAverage.length - 1] = tick; System.arraycopy(this.useAverage, 1, this.useAverage, 0, this.useAverage.length - 1); this.useAverage[this.useAverage.length - 1] = use; if ((this.nextTick - tickTime) < -1000) { this.nextTick = tickTime; } else { this.nextTick += 50; } return true; } // TODO: Fix title tick public void titleTick() { if (true || !Nukkit.ANSI) { return; } Runtime runtime = Runtime.getRuntime(); double used = NukkitMath.round((double) (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024, 2); double max = NukkitMath.round(((double) runtime.maxMemory()) / 1024 / 1024, 2); String usage = Math.round(used / max * 100) + "%"; String title = (char) 0x1b + "]0;" + this.getName() + " " + this.getNukkitVersion() + " | Online " + this.players.size() + "/" + this.getMaxPlayers() + " | Memory " + usage; if (!Nukkit.shortTitle) { title += " | U " + NukkitMath.round((this.network.getUpload() / 1024 * 1000), 2) + " D " + NukkitMath.round((this.network.getDownload() / 1024 * 1000), 2) + " kB/s"; } title += " | TPS " + this.getTicksPerSecond() + " | Load " + this.getTickUsage() + "%" + (char) 0x07; System.out.print(title); this.network.resetStatistics(); } public QueryRegenerateEvent getQueryInformation() { return this.queryRegenerateEvent; } /** * ????????? * @return String ????"Nukkit"??????? */ public String getName() { return "Nukkit"; } public boolean isRunning() { return isRunning; } /** * Nukkit?????? * @return String Nukkit? */ public String getNukkitVersion() { return Nukkit.VERSION; } /** * ????? * @return String ? */ public String getCodename() { return Nukkit.CODENAME; } /** * PE?????? * @return String Minecraft? */ public String getVersion() { return ProtocolInfo.MINECRAFT_VERSION; } /** * API????? * @return String API? */ public String getApiVersion() { return Nukkit.API_VERSION; } /** * ???? * @return String */ public String getFilePath() { return filePath; } /** * ???? * <br>????jar???? * @return String */ public String getDataPath() { return dataPath; } /** * plugins????? * <br>????getDataPath()??/plugins????????? * @return String ? * @see Server#getDataPath() */ public String getPluginPath() { return pluginPath; } public String getDefaultplugins() { return defaultplugin; } /** * ???????? * @return int ?? */ public int getMaxPlayers() { return maxPlayers; } /** * ??????? * <br>server.properties?server-port??? * @return int ? */ public int getPort() { return this.getPropertyInt("server-port", 19132); } /** * ????????? * <br>server.properties?view-distancet??? * @return int ??? */ public int getViewDistance() { return this.getPropertyInt("view-distance", 10); } /** * ??IP???? * <br>server.properties?server-ip??? * @return String IP */ public String getIp() { return this.getPropertyString("server-ip", "0.0.0.0"); } public UUID getServerUniqueId() { return this.serverID; } /** * ??????????? * @return boolean true?/false? */ public boolean getAutoSave() { return this.autoSave; } /** * ????? * @param autoSave true?/false? */ public void setAutoSave(boolean autoSave) { this.autoSave = autoSave; for (Level level : this.getLevels().values()) { level.setAutoSave(this.autoSave); } } /** * ?????? * <br>server.properties?level-type??? * <br> * <br>[] * <br>FLAT * <br>DEFAULT * @return String */ public String getLevelType() { return this.getPropertyString("level-type", "DEFAULT"); } public boolean getGenerateStructures() { return this.getPropertyBoolean("generate-structures", true); } /** * @deprecated {@link Server#getDefaultGamemode()}???????? * <br>?????? * <br>server.properties?gamemode??? * <br> * <br>[] * <br>0:?? * <br>1: * <br>2:? * <br>3: * @return int */ public int getGamemode() { return this.getPropertyInt("gamemode", 0) & 0b11; } public boolean getForceGamemode() { return this.getPropertyBoolean("force-gamemode", false); } /** * ?????????? * <br>server.properties?gamemode??? * <br> * <br>[???????:(???)] * <br>??(0) * <br>(1) * <br>?(2) * <br>(3) * <br>UNKNOWN(0-3????) * @param mode ??????????(0, 1, 2, 3) * @return String */ public static String getGamemodeString(int mode) { switch (mode) { case Player.SURVIVAL: return "%gameMode.survival"; case Player.CREATIVE: return "%gameMode.creative"; case Player.ADVENTURE: return "%gameMode.adventure"; case Player.SPECTATOR: return "%gameMode.spectator"; } return "UNKNOWN"; } public static int getGamemodeFromString(String str) { switch (str.trim().toLowerCase()) { case "0": case "survival": case "s": return Player.SURVIVAL; case "1": case "creative": case "c": return Player.CREATIVE; case "2": case "adventure": case "a": return Player.ADVENTURE; case "3": case "spectator": case "spc": case "view": case "v": return Player.SPECTATOR; } return -1; } public static int getDifficultyFromString(String str) { switch (str.trim().toLowerCase()) { case "0": case "peaceful": case "p": return 0; case "1": case "easy": case "e": return 1; case "2": case "normal": case "n": return 2; case "3": case "hard": case "h": return 3; } return -1; } /** * ?????? * <br>server.properties?difficulty??? * @return int */ public int getDifficulty() { return this.getPropertyInt("difficulty", 1); } /** * ?????????? * <br>server.properties?white-list??? * @return boolean true?/false? */ public boolean hasWhitelist() { return this.getPropertyBoolean("white-list", false); } /** * ?????????????? * <br>server.properties?spawn-protection??? * @return int ? */ public int getSpawnRadius() { return this.getPropertyInt("spawn-protection", 16); } public boolean getAllowFlight() { if (getAllowFlight == null) { getAllowFlight = this.getPropertyBoolean("allow-flight", false); } return getAllowFlight; } /** * ??????????? * <br>server.properties?hardcore??? * @return boolean true?/false? */ public boolean isHardcore() { return this.getPropertyBoolean("hardcore", false); } /** * ??????? * <br>server.properties?gamemode??? * <br> * <br>[] * <br>0:?? * <br>1: * <br>2:? * <br>3: * @return int */ public int getDefaultGamemode() { return this.getPropertyInt("gamemode", 0); } /** * ??????? * <br>server.properties?motd??? * @return String */ public String getMotd() { return this.getPropertyString("motd", "Nukkit Server For Minecraft: PE"); } public boolean getForceResources() { return this.getPropertyBoolean("force-resources", false); } /** * MainLogger???? * @return MainLogger */ public MainLogger getLogger() { return this.logger; } public EntityMetadataStore getEntityMetadata() { return entityMetadata; } public PlayerMetadataStore getPlayerMetadata() { return playerMetadata; } public LevelMetadataStore getLevelMetadata() { return levelMetadata; } /** * ????? * <br> * <br>[???: Itsu?] * <br> * <br>{@code this.getLogger().getPluginManager().registerEvents(this, this);} * @return PluginManager * @see PluginManager#registerEvents(cn.nukkit.event.Listener, Plugin) */ public PluginManager getPluginManager() { return this.pluginManager; } /** * ????? * @return CraftingManager */ public CraftingManager getCraftingManager() { return craftingManager; } /** * ????? * @return ResourcePackManager */ public ResourcePackManager getResourcePackManager() { return resourcePackManager; } /** * ???? * <br> * <br>[??:Itsu?] * <pre> * ? * {@code * TaskHandler th; * th = this.getServer().getScheduler().scheduleRepeatingTask(null, new Runnable(){ * //?? * };, tick(int)); * * * ????? * TaskHandler th; * th = this.getServer().getScheduler().scheduleDelayedRepeatingTask(null, new Runnable(){ * //?? * };, ?tick(int), tick(int)); * * * ? * th.cancel(); * </pre> * [] * <br>20tick = 1??! * @return ServerScheduler */ public ServerScheduler getScheduler() { return scheduler; } public int getTick() { return tickCounter; } public float getTicksPerSecond() { return ((float) Math.round(this.maxTick * 100)) / 100; } public float getTicksPerSecondAverage() { float sum = 0; int count = this.tickAverage.length; for (float aTickAverage : this.tickAverage) { sum += aTickAverage; } return (float) NukkitMath.round(sum / count, 2); } public float getTickUsage() { return (float) NukkitMath.round(this.maxUse * 100, 2); } public float getTickUsageAverage() { float sum = 0; int count = this.useAverage.length; for (float aUseAverage : this.useAverage) { sum += aUseAverage; } return ((float) Math.round(sum / count * 100)) / 100; } public SimpleCommandMap getCommandMap() { return commandMap; } public Map<UUID, Player> getOnlinePlayers() { return new HashMap<>(playerList); } public void addRecipe(Recipe recipe) { this.craftingManager.registerRecipe(recipe); } public IPlayer getOfflinePlayer(String name) { IPlayer result = this.getPlayerExact(name.toLowerCase()); if (result == null) { return new OfflinePlayer(this, name); } return result; } public CompoundTag getOfflinePlayerData(String name) { name = name.toLowerCase(); String path = this.getDataPath() + "players/"; File file = new File(path + name + ".dat"); if (this.shouldSavePlayerData() && file.exists()) { try { return NBTIO.readCompressed(new FileInputStream(file)); } catch (Exception e) { file.renameTo(new File(path + name + ".dat.bak")); this.logger.notice(this.getLanguage().translateString("nukkit.data.playerCorrupted", name)); } } else { this.logger.notice(this.getLanguage().translateString("nukkit.data.playerNotFound", name)); } Position spawn = this.getDefaultLevel().getSafeSpawn(); CompoundTag nbt = new CompoundTag().putLong("firstPlayed", System.currentTimeMillis() / 1000) .putLong("lastPlayed", System.currentTimeMillis() / 1000) .putList(new ListTag<DoubleTag>("Pos").add(new DoubleTag("0", spawn.x)) .add(new DoubleTag("1", spawn.y)).add(new DoubleTag("2", spawn.z))) .putString("Level", this.getDefaultLevel().getName()).putList(new ListTag<>("Inventory")) .putCompound("Achievements", new CompoundTag()).putInt("playerGameType", this.getGamemode()) .putList(new ListTag<DoubleTag>("Motion").add(new DoubleTag("0", 0)).add(new DoubleTag("1", 0)) .add(new DoubleTag("2", 0))) .putList(new ListTag<FloatTag>("Rotation").add(new FloatTag("0", 0)).add(new FloatTag("1", 0))) .putFloat("FallDistance", 0).putShort("Fire", 0).putShort("Air", 300).putBoolean("OnGround", true) .putBoolean("Invulnerable", false).putString("NameTag", name); this.saveOfflinePlayerData(name, nbt); return nbt; } public void saveOfflinePlayerData(String name, CompoundTag tag) { this.saveOfflinePlayerData(name, tag, false); } public void saveOfflinePlayerData(String name, CompoundTag tag, boolean async) { if (this.shouldSavePlayerData()) { try { if (async) { this.getScheduler().scheduleAsyncTask( new FileWriteTask(this.getDataPath() + "players/" + name.toLowerCase() + ".dat", NBTIO.writeGZIPCompressed(tag, ByteOrder.BIG_ENDIAN))); } else { Utils.writeFile(this.getDataPath() + "players/" + name.toLowerCase() + ".dat", new ByteArrayInputStream(NBTIO.writeGZIPCompressed(tag, ByteOrder.BIG_ENDIAN))); } } catch (Exception e) { this.logger.critical(this.getLanguage().translateString("nukkit.data.saveError", new String[] { name, e.getMessage() })); if (Nukkit.DEBUG > 1) { this.logger.logException(e); } } } } /** * ???????? * @param name ???????? * @return Player ??? */ public Player getPlayer(String name) { Player found = null; name = name.toLowerCase(); int delta = Integer.MAX_VALUE; for (Player player : this.getOnlinePlayers().values()) { if (player.getName().toLowerCase().startsWith(name)) { int curDelta = player.getName().length() - name.length(); if (curDelta < delta) { found = player; delta = curDelta; } if (curDelta == 0) { break; } } } return found; } public Player getPlayerExact(String name) { name = name.toLowerCase(); for (Player player : this.getOnlinePlayers().values()) { if (player.getName().toLowerCase().equals(name)) { return player; } } return null; } public Player[] matchPlayer(String partialName) { partialName = partialName.toLowerCase(); List<Player> matchedPlayer = new ArrayList<>(); for (Player player : this.getOnlinePlayers().values()) { if (player.getName().toLowerCase().equals(partialName)) { return new Player[] { player }; } else if (player.getName().toLowerCase().contains(partialName)) { matchedPlayer.add(player); } } return matchedPlayer.toArray(new Player[matchedPlayer.size()]); } public void removePlayer(Player player) { if (this.identifier.containsKey(player.rawHashCode())) { String identifier = this.identifier.get(player.rawHashCode()); this.players.remove(identifier); this.identifier.remove(player.rawHashCode()); return; } for (String identifier : new ArrayList<>(this.players.keySet())) { Player p = this.players.get(identifier); if (player == p) { this.players.remove(identifier); this.identifier.remove(player.rawHashCode()); break; } } } public Map<Integer, Level> getLevels() { return levels; } /** * ????????? * @return Level ????? */ public Level getDefaultLevel() { return defaultLevel; } public void setDefaultLevel(Level defaultLevel) { if (defaultLevel == null || (this.isLevelLoaded(defaultLevel.getFolderName()) && defaultLevel != this.defaultLevel)) { this.defaultLevel = defaultLevel; } } public boolean isLevelLoaded(String name) { return this.getLevelByName(name) != null; } public Level getLevel(int levelId) { if (this.levels.containsKey(levelId)) { return this.levels.get(levelId); } return null; } /** * ???????? * @param name ???????? * @return Level ??? */ public Level getLevelByName(String name) { for (Level level : this.getLevels().values()) { if (level.getFolderName().equals(name)) { return level; } } return null; } public boolean unloadLevel(Level level) { return this.unloadLevel(level, false); } public boolean unloadLevel(Level level, boolean forceUnload) { if (level == this.getDefaultLevel() && !forceUnload) { throw new IllegalStateException( "The default level cannot be unloaded while running, please switch levels."); } return level.unload(forceUnload); } public boolean loadLevel(String name) { if (Objects.equals(name.trim(), "")) { throw new LevelException("Invalid empty level name"); } if (this.isLevelLoaded(name)) { return true; } else if (!this.isLevelGenerated(name)) { this.logger.notice(this.getLanguage().translateString("nukkit.level.notFound", name)); return false; } String path; if (name.contains("/") || name.contains("\\")) { path = name; } else { path = this.getDataPath() + "worlds/" + name + "/"; } Class<? extends LevelProvider> provider = LevelProviderManager.getProvider(path); if (provider == null) { this.logger.error(this.getLanguage().translateString("nukkit.level.loadError", new String[] { name, "Unknown provider" })); return false; } Level level; try { level = new Level(this, name, path, provider); } catch (Exception e) { this.logger.error(this.getLanguage().translateString("nukkit.level.loadError", new String[] { name, e.getMessage() })); this.logger.logException(e); return false; } this.levels.put(level.getId(), level); level.initLevel(); this.getPluginManager().callEvent(new LevelLoadEvent(level)); level.setTickRate(this.baseTickRate); return true; } public boolean generateLevel(String name) { return this.generateLevel(name, new java.util.Random().nextLong()); } public boolean generateLevel(String name, long seed) { return this.generateLevel(name, seed, null); } public boolean generateLevel(String name, long seed, Class<? extends Generator> generator) { return this.generateLevel(name, seed, generator, new HashMap<>()); } public boolean generateLevel(String name, long seed, Class<? extends Generator> generator, Map<String, Object> options) { return generateLevel(name, seed, generator, options, null); } public boolean generateLevel(String name, long seed, Class<? extends Generator> generator, Map<String, Object> options, Class<? extends LevelProvider> provider) { if (Objects.equals(name.trim(), "") || this.isLevelGenerated(name)) { return false; } if (!options.containsKey("preset")) { options.put("preset", this.getPropertyString("generator-settings", "")); } if (generator == null) { generator = Generator.getGenerator(this.getLevelType()); } if (provider == null) { if ((provider = LevelProviderManager.getProviderByName( (String) this.getConfig("level-settings.default-format", "anvil"))) == null) { provider = LevelProviderManager.getProviderByName("anvil"); } } String path; if (name.contains("/") || name.contains("\\")) { path = name; } else { path = this.getDataPath() + "worlds/" + name + "/"; } Level level; try { provider.getMethod("generate", String.class, String.class, long.class, Class.class, Map.class) .invoke(null, path, name, seed, generator, options); level = new Level(this, name, path, provider); this.levels.put(level.getId(), level); level.initLevel(); level.setTickRate(this.baseTickRate); } catch (Exception e) { this.logger.error(this.getLanguage().translateString("nukkit.level.generationError", new String[] { name, e.getMessage() })); this.logger.logException(e); return false; } this.getPluginManager().callEvent(new LevelInitEvent(level)); this.getPluginManager().callEvent(new LevelLoadEvent(level)); /*this.getLogger().notice(this.getLanguage().translateString("nukkit.level.backgroundGeneration", name)); int centerX = (int) level.getSpawnLocation().getX() >> 4; int centerZ = (int) level.getSpawnLocation().getZ() >> 4; TreeMap<String, Integer> order = new TreeMap<>(); for (int X = -3; X <= 3; ++X) { for (int Z = -3; Z <= 3; ++Z) { int distance = X * X + Z * Z; int chunkX = X + centerX; int chunkZ = Z + centerZ; order.put(Level.chunkHash(chunkX, chunkZ), distance); } } List<Map.Entry<String, Integer>> sortList = new ArrayList<>(order.entrySet()); Collections.sort(sortList, new Comparator<Map.Entry<String, Integer>>() { @Override public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return o2.getValue() - o1.getValue(); } }); for (String index : order.keySet()) { Chunk.Entry entry = Level.getChunkXZ(index); level.populateChunk(entry.chunkX, entry.chunkZ, true); }*/ return true; } public boolean isLevelGenerated(String name) { if (Objects.equals(name.trim(), "")) { return false; } String path = this.getDataPath() + "worlds/" + name + "/"; if (this.getLevelByName(name) == null) { if (LevelProviderManager.getProvider(path) == null) { return false; } } return true; } public BaseLang getLanguage() { return baseLang; } public boolean isLanguageForced() { return forceLanguage; } public Network getNetwork() { return network; } //Revising later... public Config getConfig() { return this.config; } public Object getConfig(String variable) { return this.getConfig(variable, null); } public Object getConfig(String variable, Object defaultValue) { Object value = this.config.get(variable); return value == null ? defaultValue : value; } /** * server.properties?(Config)???? * @return Config ? */ public Config getProperties() { return this.properties; } /** * server.properties????????? * <br>???????????????? * @param variable * @return Object ??? */ public Object getProperty(String variable) { return this.getProperty(variable, null); } public Object getProperty(String variable, Object defaultValue) { return this.properties.exists(variable) ? this.properties.get(variable) : defaultValue; } /** * server.properties?????String???? * @param variable * @param value * @return void */ public void setPropertyString(String variable, String value) { this.properties.set(variable, value); this.properties.save(); } /** * server.properties?????String????? * @param variable * @return String ??? */ public String getPropertyString(String variable) { return this.getPropertyString(variable, null); } public String getPropertyString(String variable, String defaultValue) { return this.properties.exists(variable) ? (String) this.properties.get(variable) : defaultValue; } /** * server.properties?????int????? * @param variable * @return int ??? */ public int getPropertyInt(String variable) { return this.getPropertyInt(variable, null); } public int getPropertyInt(String variable, Integer defaultValue) { return this.properties.exists(variable) ? (!this.properties.get(variable).equals("") ? Integer.parseInt(String.valueOf(this.properties.get(variable))) : defaultValue) : defaultValue; } /** * server.properties?????int???? * @param variable * @param value * @return void */ public void setPropertyInt(String variable, int value) { this.properties.set(variable, value); this.properties.save(); } /** * server.properties?????boolean????? * @param variable * @return boolean ??? */ public boolean getPropertyBoolean(String variable) { return this.getPropertyBoolean(variable, null); } public boolean getPropertyBoolean(String variable, Object defaultValue) { Object value = this.properties.exists(variable) ? this.properties.get(variable) : defaultValue; if (value instanceof Boolean) { return (Boolean) value; } switch (String.valueOf(value)) { case "on": case "true": case "1": case "yes": return true; } return false; } /** * server.properties?????boolean???? * @param variable * @param value * @return void */ public void setPropertyBoolean(String variable, boolean value) { this.properties.set(variable, value ? "1" : "0"); this.properties.save(); } /** * jupiter.yml?(Config)???? * @return Config jupiter.yml? */ public Config getJupiterConfig() { return new Config(this.getDataPath() + "jupiter.yml"); } public boolean isLoadedJupiterConfig() { return !this.jupiterconfig.isEmpty(); } /** * jupiter.yml??? * @return void */ public void loadJupiterConfig() { this.jupiterconfig = this.getJupiterConfig().getAll(); } /** * jupiter.yml?????String????? * @param key * @return String ??? */ public String getJupiterConfigString(String key) { return (String) this.jupiterconfig.get(key); } /** * jupiter.yml?????int????? * @param key * @return int ??? */ public int getJupiterConfigInt(String key) { return (int) this.jupiterconfig.get(key); } /** * jupiter.yml?????Boolean????? * <br>?:?boolean??? * @param key * @return Boolean ??? */ public Boolean getJupiterConfigBoolean(String key) { return (Boolean) this.jupiterconfig.get(key); } public PluginIdentifiableCommand getPluginCommand(String name) { Command command = this.commandMap.getCommand(name); if (command instanceof PluginIdentifiableCommand) { return (PluginIdentifiableCommand) command; } else { return null; } } /** * ???Ban??????? * @return BanList ???Ban */ public BanList getNameBans() { return this.banByName; } /** * IPBan??????? * @return BanList IPBan */ public BanList getIPBans() { return this.banByIP; } /** * ???????OP???? * @param name OP???????? * @return void */ public void addOp(String name) { this.operators.set(name.toLowerCase(), true); Player player = this.getPlayerExact(name); if (player != null) { player.recalculatePermissions(); } this.operators.save(true); } /** * ????????OP??? * @param name OP??????? * @return void */ public void removeOp(String name) { this.operators.remove(name.toLowerCase()); Player player = this.getPlayerExact(name); if (player != null) { player.recalculatePermissions(); } this.operators.save(); } /** * ???????????? * @param name ???????? * @return void */ public void addWhitelist(String name) { this.whitelist.set(name.toLowerCase(), true); this.whitelist.save(true); } /** * ??????????? * @param name ???????? * @return void */ public void removeWhitelist(String name) { this.whitelist.remove(name.toLowerCase()); this.whitelist.save(true); } /** * ???????????????????? * @param name ??????? * @return boolean true????/false?????? */ public boolean isWhitelisted(String name) { return !this.hasWhitelist() || this.operators.exists(name, true) || this.whitelist.exists(name, true); } /** * ????????OP???????? * @param name ??????? * @return boolean true?OP/false??OP */ public boolean isOp(String name) { return this.operators.exists(name, true); } public Config getWhitelist() { return whitelist; } public Config getOps() { return operators; } public void reloadWhitelist() { this.whitelist.reload(); } public ServiceManager getServiceManager() { return serviceManager; } public Map<String, List<String>> getCommandAliases() { Object section = this.getConfig("aliases"); Map<String, List<String>> result = new LinkedHashMap<>(); if (section instanceof Map) { for (Map.Entry entry : (Set<Map.Entry>) ((Map) section).entrySet()) { List<String> commands = new ArrayList<>(); String key = (String) entry.getKey(); Object value = entry.getValue(); if (value instanceof List) { for (String string : (List<String>) value) { commands.add(string); } } else { commands.add((String) value); } result.put(key, commands); } } return result; } public boolean shouldSavePlayerData() { return (Boolean) this.getConfig("player.save-player-data", true); } /** * Checks the current thread against the expected primary thread for the server. * * <b>Note:</b> this method should not be used to indicate the current synchronized state of the runtime. A current thread matching the main thread indicates that it is synchronized, but a mismatch does not preclude the same assumption. * @return true if the current thread matches the expected primary thread, false otherwise */ public boolean isPrimaryThread() { return (Thread.currentThread() == currentThread); } private void registerEntities() { Entity.registerEntity("Arrow", EntityArrow.class); Entity.registerEntity("Item", EntityItem.class); Entity.registerEntity("FallingSand", EntityFallingBlock.class); Entity.registerEntity("PrimedTnt", EntityPrimedTNT.class); Entity.registerEntity("Snowball", EntitySnowball.class); Entity.registerEntity("EnderPearl", EntityEnderPearl.class); Entity.registerEntity("Painting", EntityPainting.class); Entity.registerEntity("FishingHook", EntityFishingHook.class); Entity.registerEntity("EnderCrystal", EntityEnderCrystal.class); //Mob Entity.registerEntity("Blaze", EntityBlaze.class); Entity.registerEntity("CaveSpider", EntityCaveSpider.class); Entity.registerEntity("Creeper", EntityCreeper.class); Entity.registerEntity("Enderman", EntityEnderman.class); Entity.registerEntity("Endermite", EntityEndermite.class); Entity.registerEntity("Ghast", EntityGhast.class); Entity.registerEntity("Guardian", EntityGuardian.class); Entity.registerEntity("Hask", EntityHask.class); Entity.registerEntity("MagmaCube", EntityMagmaCube.class); Entity.registerEntity("Shulker", EntityShulker.class); Entity.registerEntity("Silverfish", EntitySilverfish.class); Entity.registerEntity("Skeleton", EntitySkeleton.class); Entity.registerEntity("Slime", EntitySlime.class); Entity.registerEntity("Spider", EntitySpider.class); Entity.registerEntity("Stray", EntityStray.class); Entity.registerEntity("Witch", EntityWitch.class); Entity.registerEntity("WitherSkeleton", EntityWitherSkeleton.class); Entity.registerEntity("Zombie", EntityZombie.class); Entity.registerEntity("ZombiePigman", EntityZombiePigman.class); Entity.registerEntity("ZombieVillager", EntityZombieVillager.class); //TODO: more mobs Entity.registerEntity("Bat", EntityBat.class); Entity.registerEntity("Chicken", EntityChicken.class); Entity.registerEntity("Cow", EntityCow.class); Entity.registerEntity("Donkey", EntityDonkey.class); Entity.registerEntity("Horse", EntityHorse.class); Entity.registerEntity("Mooshroom", EntityMooshroom.class); Entity.registerEntity("Mule", EntityMule.class); Entity.registerEntity("Ocelot", EntityOcelot.class); Entity.registerEntity("Pig", EntityPig.class); Entity.registerEntity("PolarBear", EntityPolarBear.class); Entity.registerEntity("Rabbit", EntityRabbit.class); Entity.registerEntity("Sheep", EntitySheep.class); Entity.registerEntity("SkeletonHorse", EntitySkeletonHorse.class); Entity.registerEntity("Squid", EntitySquid.class); Entity.registerEntity("Villager", EntityVillager.class); Entity.registerEntity("Wolf", EntityWolf.class); Entity.registerEntity("ZombieHorse", EntityZombieHorse.class); //Bosses Entity.registerEntity("ElderGuardian", EntityElderGuardian.class); Entity.registerEntity("EnderDragon", EntityEnderDragon.class); Entity.registerEntity("EnderWither", EntityWither.class); Entity.registerEntity("ThrownExpBottle", EntityExpBottle.class); Entity.registerEntity("XpOrb", EntityXPOrb.class); Entity.registerEntity("ThrownPotion", EntityPotion.class); Entity.registerEntity("Human", EntityHuman.class, true); Entity.registerEntity("MinecartRideable", EntityMinecartEmpty.class); Entity.registerEntity("MinecartChest", EntityMinecartChest.class); Entity.registerEntity("MinecartHopper", EntityMinecartHopper.class); Entity.registerEntity("MinecartTnt", EntityMinecartTNT.class); Entity.registerEntity("Boat", EntityBoat.class); Entity.registerEntity("Lightning", EntityLightning.class); } private void registerBlockEntities() { BlockEntity.registerBlockEntity(BlockEntity.FURNACE, BlockEntityFurnace.class); BlockEntity.registerBlockEntity(BlockEntity.CHEST, BlockEntityChest.class); BlockEntity.registerBlockEntity(BlockEntity.SIGN, BlockEntitySign.class); BlockEntity.registerBlockEntity(BlockEntity.ENCHANT_TABLE, BlockEntityEnchantTable.class); BlockEntity.registerBlockEntity(BlockEntity.SKULL, BlockEntitySkull.class); BlockEntity.registerBlockEntity(BlockEntity.FLOWER_POT, BlockEntityFlowerPot.class); BlockEntity.registerBlockEntity(BlockEntity.BREWING_STAND, BlockEntityBrewingStand.class); BlockEntity.registerBlockEntity(BlockEntity.ITEM_FRAME, BlockEntityItemFrame.class); BlockEntity.registerBlockEntity(BlockEntity.CAULDRON, BlockEntityCauldron.class); BlockEntity.registerBlockEntity(BlockEntity.ENDER_CHEST, BlockEntityEnderChest.class); BlockEntity.registerBlockEntity(BlockEntity.BEACON, BlockEntityBeacon.class); } /** * ?????? * @return Server ?? */ public static Server getInstance() { return instance; } }