minecraft-source/src/net/minecraft/server/MinecraftServer.java

1621 lines
62 KiB
Java

package net.minecraft.server;
import org.apache.logging.log4j.LogManager;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.Block;
import java.lang.management.ThreadMXBean;
import java.util.function.Function;
import java.util.Comparator;
import java.lang.management.ThreadInfo;
import java.lang.management.ManagementFactory;
import com.google.common.base.Splitter;
import java.io.Writer;
import java.nio.file.OpenOption;
import net.minecraft.resources.ResourceLocation;
import java.nio.file.Files;
import java.nio.file.attribute.FileAttribute;
import net.minecraft.server.players.ServerOpListEntry;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec2;
import net.minecraft.core.Vec3i;
import net.minecraft.world.phys.Vec3;
import net.minecraft.server.players.UserWhiteList;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.packs.Pack;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraft.network.protocol.game.ClientboundChangeDifficultyPacket;
import java.util.function.Consumer;
import java.nio.file.Path;
import joptsimple.OptionSet;
import net.minecraft.DefaultUncaughtExceptionHandler;
import java.awt.GraphicsEnvironment;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.server.level.progress.LoggerChunkProgressListener;
import net.minecraft.util.datafix.DataFixers;
import java.util.Optional;
import java.util.UUID;
import net.minecraft.server.dedicated.DedicatedServerSettings;
import java.nio.file.Paths;
import joptsimple.OptionSpec;
import joptsimple.OptionParser;
import net.minecraft.gametest.framework.GameTestTicker;
import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientboundSetTimePacket;
import net.minecraft.core.Registry;
import java.util.Collections;
import java.util.Arrays;
import net.minecraft.server.level.ServerPlayer;
import com.mojang.authlib.GameProfile;
import java.util.function.BooleanSupplier;
import java.nio.ByteBuffer;
import java.awt.image.BufferedImage;
import io.netty.buffer.ByteBuf;
import java.util.Base64;
import java.io.OutputStream;
import java.awt.image.RenderedImage;
import io.netty.buffer.ByteBufOutputStream;
import org.apache.commons.lang3.Validate;
import javax.imageio.ImageIO;
import io.netty.buffer.Unpooled;
import java.util.Date;
import java.text.SimpleDateFormat;
import net.minecraft.SharedConstants;
import net.minecraft.network.chat.TextComponent;
import net.minecraft.world.level.LevelConflictException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import it.unimi.dsi.fastutil.longs.LongIterator;
import net.minecraft.server.level.ServerChunkCache;
import net.minecraft.core.BlockPos;
import net.minecraft.world.level.ForcedChunksSavedData;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.level.ChunkPos;
import java.util.Collection;
import net.minecraft.server.packs.repository.RepositorySource;
import net.minecraft.server.packs.repository.ServerPacksSource;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.Difficulty;
import net.minecraft.world.level.GameType;
import java.util.Iterator;
import net.minecraft.server.level.DerivedServerLevel;
import net.minecraft.ReportedException;
import net.minecraft.CrashReport;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.world.level.storage.LevelStorage;
import com.google.gson.JsonElement;
import net.minecraft.world.level.LevelType;
import net.minecraft.world.level.storage.LevelData;
import net.minecraft.util.Mth;
import net.minecraft.util.worldupdate.WorldUpgrader;
import net.minecraft.util.ProgressListener;
import net.minecraft.network.chat.TranslatableComponent;
import java.io.IOException;
import net.minecraft.world.level.saveddata.SavedData;
import net.minecraft.world.level.saveddata.SaveDataDirtyRunnable;
import net.minecraft.world.scores.Scoreboard;
import net.minecraft.world.scores.ScoreboardSaveData;
import net.minecraft.world.level.storage.DimensionDataStorage;
import net.minecraft.server.packs.resources.PreparableReloadListener;
import net.minecraft.server.packs.resources.SimpleReloadableResourceManager;
import net.minecraft.server.packs.PackType;
import com.google.common.collect.Maps;
import com.google.common.collect.Lists;
import net.minecraft.Util;
import java.util.concurrent.Executor;
import net.minecraft.util.FrameTimer;
import net.minecraft.world.level.storage.loot.LootTables;
import net.minecraft.world.level.storage.loot.PredicateManager;
import net.minecraft.server.bossevents.CustomBossEvents;
import net.minecraft.world.level.storage.CommandStorage;
import net.minecraft.tags.TagManager;
import net.minecraft.world.item.crafting.RecipeManager;
import net.minecraft.commands.Commands;
import net.minecraft.server.packs.repository.FolderRepositorySource;
import net.minecraft.server.packs.repository.UnopenedPack;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.server.packs.resources.ReloadableResourceManager;
import net.minecraft.server.players.GameProfileCache;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import net.minecraft.network.chat.Component;
import java.security.KeyPair;
import javax.annotation.Nullable;
import java.net.Proxy;
import net.minecraft.server.players.PlayerList;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.level.dimension.DimensionType;
import java.util.Map;
import com.mojang.datafixers.DataFixer;
import java.util.Random;
import net.minecraft.network.protocol.status.ServerStatus;
import net.minecraft.server.level.progress.ChunkProgressListenerFactory;
import net.minecraft.server.network.ServerConnectionListener;
import net.minecraft.util.profiling.GameProfiler;
import java.util.List;
import net.minecraft.world.Snooper;
import net.minecraft.world.level.storage.LevelStorageSource;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.util.Unit;
import java.util.concurrent.CompletableFuture;
import java.io.File;
import org.apache.logging.log4j.Logger;
import net.minecraft.commands.CommandSource;
import net.minecraft.world.SnooperPopulator;
import net.minecraft.util.thread.ReentrantBlockableEventLoop;
public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTask> implements SnooperPopulator, CommandSource, AutoCloseable, Runnable {
private static final Logger LOGGER;
public static final File USERID_CACHE_FILE;
private static final CompletableFuture<Unit> DATA_RELOAD_INITIAL_TASK;
public static final LevelSettings DEMO_SETTINGS;
private final LevelStorageSource storageSource;
private final Snooper snooper;
private final File universe;
private final List<Runnable> tickables;
private final GameProfiler profiler;
private final ServerConnectionListener connection;
protected final ChunkProgressListenerFactory progressListenerFactory;
private final ServerStatus status;
private final Random random;
private final DataFixer fixerUpper;
private String localIp;
private int port;
private final Map<DimensionType, ServerLevel> levels;
private PlayerList playerList;
private volatile boolean running;
private boolean stopped;
private int tickCount;
protected final Proxy proxy;
private boolean onlineMode;
private boolean preventProxyConnections;
private boolean animals;
private boolean npcs;
private boolean pvp;
private boolean allowFlight;
@Nullable
private String motd;
private int maxBuildHeight;
private int playerIdleTimeout;
public final long[] tickTimes;
@Nullable
private KeyPair keyPair;
@Nullable
private String singleplayerName;
private final String levelIdName;
@Nullable
private String levelName;
private boolean isDemo;
private boolean levelHasStartingBonusChest;
private String resourcePack;
private String resourcePackHash;
private volatile boolean isReady;
private long lastOverloadWarning;
@Nullable
private Component startupState;
private boolean delayProfilerStart;
private boolean forceGameType;
@Nullable
private final YggdrasilAuthenticationService authenticationService;
private final MinecraftSessionService sessionService;
private final GameProfileRepository profileRepository;
private final GameProfileCache profileCache;
private long lastServerStatus;
protected final Thread serverThread;
private long nextTickTime;
private long delayedTasksMaxNextTickTime;
private boolean mayHaveDelayedTasks;
private boolean hasWorldScreenshot;
private final ReloadableResourceManager resources;
private final PackRepository<UnopenedPack> packRepository;
@Nullable
private FolderRepositorySource folderPackSource;
private final Commands commands;
private final RecipeManager recipes;
private final TagManager tags;
private final ServerScoreboard scoreboard;
@Nullable
private CommandStorage commandStorage;
private final CustomBossEvents customBossEvents;
private final PredicateManager predicateManager;
private final LootTables lootTables;
private final ServerAdvancementManager advancements;
private final ServerFunctionManager functions;
private final FrameTimer frameTimer;
private boolean enforceWhitelist;
private boolean forceUpgrade;
private boolean eraseCache;
private float averageTickTime;
private final Executor executor;
@Nullable
private String serverId;
public MinecraftServer(final File file, final Proxy proxy, final DataFixer dataFixer, final Commands cr, final YggdrasilAuthenticationService yggdrasilAuthenticationService, final MinecraftSessionService minecraftSessionService, final GameProfileRepository gameProfileRepository, final GameProfileCache zk, final ChunkProgressListenerFactory xn, final String string) {
super("Server");
this.snooper = new Snooper("server", this, Util.getMillis());
this.tickables = Lists.newArrayList();
this.profiler = new GameProfiler(this::getTickCount);
this.status = new ServerStatus();
this.random = new Random();
this.port = -1;
this.levels = Maps.newIdentityHashMap();
this.running = true;
this.tickTimes = new long[100];
this.resourcePack = "";
this.resourcePackHash = "";
this.serverThread = Util.<Thread>make(new Thread(this, "Server thread"), thread -> thread.setUncaughtExceptionHandler((thread, throwable) -> MinecraftServer.LOGGER.error(throwable)));
this.nextTickTime = Util.getMillis();
this.resources = new SimpleReloadableResourceManager(PackType.SERVER_DATA, this.serverThread);
this.packRepository = new PackRepository<UnopenedPack>(UnopenedPack::new);
this.recipes = new RecipeManager();
this.tags = new TagManager();
this.scoreboard = new ServerScoreboard(this);
this.customBossEvents = new CustomBossEvents(this);
this.predicateManager = new PredicateManager();
this.lootTables = new LootTables(this.predicateManager);
this.advancements = new ServerAdvancementManager();
this.functions = new ServerFunctionManager(this);
this.frameTimer = new FrameTimer();
this.proxy = proxy;
this.commands = cr;
this.authenticationService = yggdrasilAuthenticationService;
this.sessionService = minecraftSessionService;
this.profileRepository = gameProfileRepository;
this.profileCache = zk;
this.universe = file;
this.connection = new ServerConnectionListener(this);
this.progressListenerFactory = xn;
this.storageSource = new LevelStorageSource(file.toPath(), file.toPath().resolve("../backups"), dataFixer);
this.fixerUpper = dataFixer;
this.resources.registerReloadListener(this.tags);
this.resources.registerReloadListener(this.predicateManager);
this.resources.registerReloadListener(this.recipes);
this.resources.registerReloadListener(this.lootTables);
this.resources.registerReloadListener(this.functions);
this.resources.registerReloadListener(this.advancements);
this.executor = Util.backgroundExecutor();
this.levelIdName = string;
}
private void readScoreboard(final DimensionDataStorage cri) {
final ScoreboardSaveData cwj3 = cri.<ScoreboardSaveData>computeIfAbsent(ScoreboardSaveData::new, "scoreboard");
cwj3.setScoreboard(this.getScoreboard());
this.getScoreboard().addDirtyListener(new SaveDataDirtyRunnable(cwj3));
}
protected abstract boolean initServer() throws IOException;
protected void ensureLevelConversion(final String string) {
if (this.getStorageSource().requiresConversion(string)) {
MinecraftServer.LOGGER.info("Converting map!");
this.setServerStartupState(new TranslatableComponent("menu.convertingLevel", new Object[0]));
this.getStorageSource().convertLevel(string, new ProgressListener() {
private long timeStamp = Util.getMillis();
@Override
public void progressStartNoAbort(final Component lf) {
}
@Override
public void progressStart(final Component lf) {
}
@Override
public void progressStagePercentage(final int integer) {
if (Util.getMillis() - this.timeStamp >= 1000L) {
this.timeStamp = Util.getMillis();
MinecraftServer.LOGGER.info("Converting... {}%", integer);
}
}
@Override
public void stop() {
}
@Override
public void progressStage(final Component lf) {
}
});
}
if (this.forceUpgrade) {
MinecraftServer.LOGGER.info("Forcing world upgrade!");
final LevelData crj3 = this.getStorageSource().getDataTagFor(this.getLevelIdName());
if (crj3 != null) {
final WorldUpgrader aiw4 = new WorldUpgrader(this.getLevelIdName(), this.getStorageSource(), crj3, this.eraseCache);
Component lf5 = null;
while (!aiw4.isFinished()) {
final Component lf6 = aiw4.getStatus();
if (lf5 != lf6) {
lf5 = lf6;
MinecraftServer.LOGGER.info(aiw4.getStatus().getString());
}
final int integer7 = aiw4.getTotalChunks();
if (integer7 > 0) {
final int integer8 = aiw4.getConverted() + aiw4.getSkipped();
MinecraftServer.LOGGER.info("{}% completed ({} / {} chunks)...", Mth.floor(integer8 / (float)integer7 * 100.0f), integer8, integer7);
}
if (this.isStopped()) {
aiw4.cancel();
}
else {
try {
Thread.sleep(1000L);
}
catch (InterruptedException ex) {}
}
}
}
}
}
protected synchronized void setServerStartupState(final Component lf) {
this.startupState = lf;
}
protected void loadLevel(final String string1, final String string2, final long long3, final LevelType bka, final JsonElement jsonElement) {
this.ensureLevelConversion(string1);
this.setServerStartupState(new TranslatableComponent("menu.loadingLevel", new Object[0]));
final LevelStorage crk8 = this.getStorageSource().selectLevel(string1, this);
this.detectBundledResources(this.getLevelIdName(), crk8);
LevelData crj10 = crk8.prepareLevel();
LevelSettings bjx9;
if (crj10 == null) {
if (this.isDemo()) {
bjx9 = MinecraftServer.DEMO_SETTINGS;
}
else {
bjx9 = new LevelSettings(long3, this.getDefaultGameType(), this.canGenerateStructures(), this.isHardcore(), bka);
bjx9.setLevelTypeOptions(jsonElement);
if (this.levelHasStartingBonusChest) {
bjx9.enableStartingBonusItems();
}
}
crj10 = new LevelData(bjx9, string2);
}
else {
crj10.setLevelName(string2);
bjx9 = new LevelSettings(crj10);
}
this.loadDataPacks(crk8.getFolder(), crj10);
final ChunkProgressListener xm11 = this.progressListenerFactory.create(11);
this.createLevels(crk8, crj10, bjx9, xm11);
this.setDifficulty(this.getDefaultDifficulty(), true);
this.prepareLevels(xm11);
}
protected void createLevels(final LevelStorage crk, final LevelData crj, final LevelSettings bjx, final ChunkProgressListener xm) {
if (this.isDemo()) {
crj.setLevelSettings(MinecraftServer.DEMO_SETTINGS);
}
final ServerLevel xd6 = new ServerLevel(this, this.executor, crk, crj, DimensionType.OVERWORLD, this.profiler, xm);
this.levels.put(DimensionType.OVERWORLD, xd6);
final DimensionDataStorage cri7 = xd6.getDataStorage();
this.readScoreboard(cri7);
this.commandStorage = new CommandStorage(cri7);
xd6.getWorldBorder().readBorderData(crj);
final ServerLevel xd7 = this.getLevel(DimensionType.OVERWORLD);
if (!crj.isInitialized()) {
try {
xd7.setInitialSpawn(bjx);
if (crj.getGeneratorType() == LevelType.DEBUG_ALL_BLOCK_STATES) {
this.setupDebugLevel(crj);
}
crj.setInitialized(true);
}
catch (Throwable throwable9) {
final CrashReport h10 = CrashReport.forThrowable(throwable9, "Exception initializing level");
try {
xd7.fillReportDetails(h10);
}
catch (Throwable t) {}
throw new ReportedException(h10);
}
crj.setInitialized(true);
}
this.getPlayerList().setLevel(xd7);
if (crj.getCustomBossEvents() != null) {
this.getCustomBossEvents().load(crj.getCustomBossEvents());
}
for (final DimensionType cbf10 : DimensionType.getAllTypes()) {
if (cbf10 == DimensionType.OVERWORLD) {
continue;
}
this.levels.put(cbf10, new DerivedServerLevel(xd7, this, this.executor, crk, cbf10, this.profiler, xm));
}
}
private void setupDebugLevel(final LevelData crj) {
crj.setGenerateMapFeatures(false);
crj.setAllowCommands(true);
crj.setRaining(false);
crj.setThundering(false);
crj.setClearWeatherTime(1000000000);
crj.setDayTime(6000L);
crj.setGameType(GameType.SPECTATOR);
crj.setHardcore(false);
crj.setDifficulty(Difficulty.PEACEFUL);
crj.setDifficultyLocked(true);
crj.getGameRules().<GameRules.BooleanValue>getRule(GameRules.RULE_DAYLIGHT).set(false, this);
}
protected void loadDataPacks(final File file, final LevelData crj) {
this.packRepository.addSource(new ServerPacksSource());
this.folderPackSource = new FolderRepositorySource(new File(file, "datapacks"));
this.packRepository.addSource(this.folderPackSource);
this.packRepository.reload();
final List<UnopenedPack> list4 = Lists.newArrayList();
for (final String string6 : crj.getEnabledDataPacks()) {
final UnopenedPack yt7 = this.packRepository.getPack(string6);
if (yt7 != null) {
list4.add(yt7);
}
else {
MinecraftServer.LOGGER.warn("Missing data pack {}", string6);
}
}
this.packRepository.setSelected(list4);
this.updateSelectedPacks(crj);
this.refreshRegistries();
}
protected void prepareLevels(final ChunkProgressListener xm) {
this.setServerStartupState(new TranslatableComponent("menu.generatingTerrain", new Object[0]));
final ServerLevel xd3 = this.getLevel(DimensionType.OVERWORLD);
MinecraftServer.LOGGER.info("Preparing start region for dimension " + DimensionType.getName(xd3.dimension.getType()));
final BlockPos fk4 = xd3.getSharedSpawnPos();
xm.updateSpawnPos(new ChunkPos(fk4));
final ServerChunkCache xb5 = xd3.getChunkSource();
xb5.getLightEngine().setTaskPerBatch(500);
this.nextTickTime = Util.getMillis();
xb5.<Unit>addRegionTicket(TicketType.START, new ChunkPos(fk4), 11, Unit.INSTANCE);
while (xb5.getTickingGenerated() != 441) {
this.nextTickTime = Util.getMillis() + 10L;
this.waitUntilNextTick();
}
this.nextTickTime = Util.getMillis() + 10L;
this.waitUntilNextTick();
for (final DimensionType cbf7 : DimensionType.getAllTypes()) {
final ForcedChunksSavedData bjo8 = this.getLevel(cbf7).getDataStorage().<ForcedChunksSavedData>get(ForcedChunksSavedData::new, "chunks");
if (bjo8 != null) {
final ServerLevel xd4 = this.getLevel(cbf7);
final LongIterator longIterator10 = bjo8.getChunks().iterator();
while (longIterator10.hasNext()) {
final long long11 = longIterator10.nextLong();
final ChunkPos bje13 = new ChunkPos(long11);
xd4.getChunkSource().updateChunkForced(bje13, true);
}
}
}
this.nextTickTime = Util.getMillis() + 10L;
this.waitUntilNextTick();
xm.stop();
xb5.getLightEngine().setTaskPerBatch(5);
}
protected void detectBundledResources(final String string, final LevelStorage crk) {
final File file4 = new File(crk.getFolder(), "resources.zip");
if (file4.isFile()) {
try {
this.setResourcePack("level://" + URLEncoder.encode(string, StandardCharsets.UTF_8.toString()) + "/" + "resources.zip", "");
}
catch (UnsupportedEncodingException unsupportedEncodingException5) {
MinecraftServer.LOGGER.warn("Something went wrong url encoding {}", string);
}
}
}
public abstract boolean canGenerateStructures();
public abstract GameType getDefaultGameType();
public abstract Difficulty getDefaultDifficulty();
public abstract boolean isHardcore();
public abstract int getOperatorUserPermissionLevel();
public abstract int getFunctionCompilationLevel();
public abstract boolean shouldRconBroadcast();
public boolean saveAllChunks(final boolean boolean1, final boolean boolean2, final boolean boolean3) {
boolean boolean4 = false;
for (final ServerLevel xd7 : this.getAllLevels()) {
if (!boolean1) {
MinecraftServer.LOGGER.info("Saving chunks for level '{}'/{}", xd7.getLevelData().getLevelName(), DimensionType.getName(xd7.dimension.getType()));
}
try {
xd7.save(null, boolean2, xd7.noSave && !boolean3);
}
catch (LevelConflictException bjv8) {
MinecraftServer.LOGGER.warn(bjv8.getMessage());
}
boolean4 = true;
}
final ServerLevel xd8 = this.getLevel(DimensionType.OVERWORLD);
final LevelData crj7 = xd8.getLevelData();
xd8.getWorldBorder().saveWorldBorderData(crj7);
crj7.setCustomBossEvents(this.getCustomBossEvents().save());
xd8.getLevelStorage().saveLevelData(crj7, this.getPlayerList().getSingleplayerData());
return boolean4;
}
@Override
public void close() {
this.stopServer();
}
protected void stopServer() {
MinecraftServer.LOGGER.info("Stopping server");
if (this.getConnection() != null) {
this.getConnection().stop();
}
if (this.playerList != null) {
MinecraftServer.LOGGER.info("Saving players");
this.playerList.saveAll();
this.playerList.removeAll();
}
MinecraftServer.LOGGER.info("Saving worlds");
for (final ServerLevel xd3 : this.getAllLevels()) {
if (xd3 != null) {
xd3.noSave = false;
}
}
this.saveAllChunks(false, true, false);
for (final ServerLevel xd3 : this.getAllLevels()) {
if (xd3 != null) {
try {
xd3.close();
}
catch (IOException iOException4) {
MinecraftServer.LOGGER.error("Exception closing the level", (Throwable)iOException4);
}
}
}
if (this.snooper.isStarted()) {
this.snooper.interrupt();
}
}
public String getLocalIp() {
return this.localIp;
}
public void setLocalIp(final String string) {
this.localIp = string;
}
public boolean isRunning() {
return this.running;
}
public void halt(final boolean boolean1) {
this.running = false;
if (boolean1) {
try {
this.serverThread.join();
}
catch (InterruptedException interruptedException3) {
MinecraftServer.LOGGER.error("Error while shutting down", (Throwable)interruptedException3);
}
}
}
@Override
public void run() {
try {
if (this.initServer()) {
this.nextTickTime = Util.getMillis();
this.status.setDescription(new TextComponent(this.motd));
this.status.setVersion(new ServerStatus.Version(SharedConstants.getCurrentVersion().getName(), SharedConstants.getCurrentVersion().getProtocolVersion()));
this.updateStatusIcon(this.status);
while (this.running) {
final long long2 = Util.getMillis() - this.nextTickTime;
if (long2 > 2000L && this.nextTickTime - this.lastOverloadWarning >= 15000L) {
final long long3 = long2 / 50L;
MinecraftServer.LOGGER.warn("Can't keep up! Is the server overloaded? Running {}ms or {} ticks behind", long2, long3);
this.nextTickTime += long3 * 50L;
this.lastOverloadWarning = this.nextTickTime;
}
this.nextTickTime += 50L;
if (this.delayProfilerStart) {
this.delayProfilerStart = false;
this.profiler.continuous().enable();
}
this.profiler.startTick();
this.profiler.push("tick");
this.tickServer(this::haveTime);
this.profiler.popPush("nextTickWait");
this.mayHaveDelayedTasks = true;
this.delayedTasksMaxNextTickTime = Math.max(Util.getMillis() + 50L, this.nextTickTime);
this.waitUntilNextTick();
this.profiler.pop();
this.profiler.endTick();
this.isReady = true;
}
}
else {
this.onServerCrash(null);
}
}
catch (Throwable throwable2) {
MinecraftServer.LOGGER.error("Encountered an unexpected exception", throwable2);
CrashReport h3;
if (throwable2 instanceof ReportedException) {
h3 = this.fillReport(((ReportedException)throwable2).getReport());
}
else {
h3 = this.fillReport(new CrashReport("Exception in server tick loop", throwable2));
}
final File file4 = new File(new File(this.getServerDirectory(), "crash-reports"), "crash-" + new SimpleDateFormat("yyyy-MM-dd_HH.mm.ss").format(new Date()) + "-server.txt");
if (h3.saveToFile(file4)) {
MinecraftServer.LOGGER.error("This crash report has been saved to: {}", file4.getAbsolutePath());
}
else {
MinecraftServer.LOGGER.error("We were unable to save this crash report to disk.");
}
this.onServerCrash(h3);
try {
this.stopped = true;
this.stopServer();
}
catch (Throwable throwable2) {
MinecraftServer.LOGGER.error("Exception stopping the server", throwable2);
}
finally {
this.onServerExit();
}
}
finally {
try {
this.stopped = true;
this.stopServer();
}
catch (Throwable throwable3) {
MinecraftServer.LOGGER.error("Exception stopping the server", throwable3);
this.onServerExit();
}
finally {
this.onServerExit();
}
}
}
private boolean haveTime() {
return this.runningTask() || Util.getMillis() < (this.mayHaveDelayedTasks ? this.delayedTasksMaxNextTickTime : this.nextTickTime);
}
protected void waitUntilNextTick() {
this.runAllTasks();
this.managedBlock(() -> !this.haveTime());
}
@Override
protected TickTask wrapRunnable(final Runnable runnable) {
return new TickTask(this.tickCount, runnable);
}
@Override
protected boolean shouldRun(final TickTask tb) {
return tb.getTick() + 3 < this.tickCount || this.haveTime();
}
public boolean pollTask() {
final boolean boolean2 = this.pollTaskInternal();
return this.mayHaveDelayedTasks = boolean2;
}
private boolean pollTaskInternal() {
if (super.pollTask()) {
return true;
}
if (this.haveTime()) {
for (final ServerLevel xd3 : this.getAllLevels()) {
if (xd3.getChunkSource().pollTask()) {
return true;
}
}
}
return false;
}
public void updateStatusIcon(final ServerStatus rw) {
File file3 = this.getFile("server-icon.png");
if (!file3.exists()) {
file3 = this.getStorageSource().getFile(this.getLevelIdName(), "icon.png");
}
if (file3.isFile()) {
final ByteBuf byteBuf4 = Unpooled.buffer();
try {
final BufferedImage bufferedImage5 = ImageIO.read(file3);
Validate.validState(bufferedImage5.getWidth() == 64, "Must be 64 pixels wide", new Object[0]);
Validate.validState(bufferedImage5.getHeight() == 64, "Must be 64 pixels high", new Object[0]);
ImageIO.write(bufferedImage5, "PNG", (OutputStream)new ByteBufOutputStream(byteBuf4));
final ByteBuffer byteBuffer6 = Base64.getEncoder().encode(byteBuf4.nioBuffer());
rw.setFavicon("data:image/png;base64," + StandardCharsets.UTF_8.decode(byteBuffer6));
}
catch (Exception exception5) {
MinecraftServer.LOGGER.error("Couldn't load server icon", (Throwable)exception5);
}
finally {
byteBuf4.release();
}
}
}
public boolean hasWorldScreenshot() {
return this.hasWorldScreenshot = (this.hasWorldScreenshot || this.getWorldScreenshotFile().isFile());
}
public File getWorldScreenshotFile() {
return this.getStorageSource().getFile(this.getLevelIdName(), "icon.png");
}
public File getServerDirectory() {
return new File(".");
}
protected void onServerCrash(final CrashReport h) {
}
protected void onServerExit() {
}
protected void tickServer(final BooleanSupplier booleanSupplier) {
final long long3 = Util.getNanos();
++this.tickCount;
this.tickChildren(booleanSupplier);
if (long3 - this.lastServerStatus >= 5000000000L) {
this.lastServerStatus = long3;
this.status.setPlayers(new ServerStatus.Players(this.getMaxPlayers(), this.getPlayerCount()));
final GameProfile[] arr5 = new GameProfile[Math.min(this.getPlayerCount(), 12)];
final int integer6 = Mth.nextInt(this.random, 0, this.getPlayerCount() - arr5.length);
for (int integer7 = 0; integer7 < arr5.length; ++integer7) {
arr5[integer7] = this.playerList.getPlayers().get(integer6 + integer7).getGameProfile();
}
Collections.shuffle(Arrays.<GameProfile>asList(arr5));
this.status.getPlayers().setSample(arr5);
}
if (this.tickCount % 6000 == 0) {
MinecraftServer.LOGGER.debug("Autosave started");
this.profiler.push("save");
this.playerList.saveAll();
this.saveAllChunks(true, false, false);
this.profiler.pop();
MinecraftServer.LOGGER.debug("Autosave finished");
}
this.profiler.push("snooper");
if (!this.snooper.isStarted() && this.tickCount > 100) {
this.snooper.start();
}
if (this.tickCount % 6000 == 0) {
this.snooper.prepare();
}
this.profiler.pop();
this.profiler.push("tallying");
final long[] tickTimes = this.tickTimes;
final int n = this.tickCount % 100;
final long n2 = Util.getNanos() - long3;
tickTimes[n] = n2;
final long long4 = n2;
this.averageTickTime = this.averageTickTime * 0.8f + long4 / 1000000.0f * 0.19999999f;
final long long5 = Util.getNanos();
this.frameTimer.logFrameDuration(long5 - long3);
this.profiler.pop();
}
protected void tickChildren(final BooleanSupplier booleanSupplier) {
this.profiler.push("commandFunctions");
this.getFunctions().tick();
this.profiler.popPush("levels");
for (final ServerLevel xd4 : this.getAllLevels()) {
if (xd4.dimension.getType() == DimensionType.OVERWORLD || this.isNetherEnabled()) {
final ServerLevel serverLevel;
this.profiler.push(() -> serverLevel.getLevelData().getLevelName() + " " + Registry.DIMENSION_TYPE.getKey(serverLevel.dimension.getType()));
if (this.tickCount % 20 == 0) {
this.profiler.push("timeSync");
this.playerList.broadcastAll(new ClientboundSetTimePacket(xd4.getGameTime(), xd4.getDayTime(), xd4.getGameRules().getBoolean(GameRules.RULE_DAYLIGHT)), xd4.dimension.getType());
this.profiler.pop();
}
this.profiler.push("tick");
try {
xd4.tick(booleanSupplier);
}
catch (Throwable throwable5) {
final CrashReport h6 = CrashReport.forThrowable(throwable5, "Exception ticking world");
xd4.fillReportDetails(h6);
throw new ReportedException(h6);
}
this.profiler.pop();
this.profiler.pop();
}
}
this.profiler.popPush("connection");
this.getConnection().tick();
this.profiler.popPush("players");
this.playerList.tick();
if (SharedConstants.IS_RUNNING_IN_IDE) {
GameTestTicker.singleton.tick();
}
this.profiler.popPush("server gui refresh");
for (int integer3 = 0; integer3 < this.tickables.size(); ++integer3) {
this.tickables.get(integer3).run();
}
this.profiler.pop();
}
public boolean isNetherEnabled() {
return true;
}
public void addTickable(final Runnable runnable) {
this.tickables.add(runnable);
}
public static void main(final String[] arr) {
final OptionParser optionParser2 = new OptionParser();
final OptionSpec<Void> optionSpec3 = optionParser2.accepts("nogui");
final OptionSpec<Void> optionSpec4 = optionParser2.accepts("initSettings", "Initializes 'server.properties' and 'eula.txt', then quits");
final OptionSpec<Void> optionSpec5 = optionParser2.accepts("demo");
final OptionSpec<Void> optionSpec6 = optionParser2.accepts("bonusChest");
final OptionSpec<Void> optionSpec7 = optionParser2.accepts("forceUpgrade");
final OptionSpec<Void> optionSpec8 = optionParser2.accepts("eraseCache");
final OptionSpec<Void> optionSpec9 = optionParser2.accepts("help").forHelp();
final OptionSpec<String> optionSpec10 = optionParser2.accepts("singleplayer").withRequiredArg();
final OptionSpec<String> optionSpec11 = optionParser2.accepts("universe").withRequiredArg().defaultsTo(".", new String[0]);
final OptionSpec<String> optionSpec12 = optionParser2.accepts("world").withRequiredArg();
final OptionSpec<Integer> optionSpec13 = optionParser2.accepts("port").withRequiredArg().<Integer>ofType(Integer.class).defaultsTo(-1, new Integer[0]);
final OptionSpec<String> optionSpec14 = optionParser2.accepts("serverId").withRequiredArg();
final OptionSpec<String> optionSpec15 = optionParser2.nonOptions();
try {
final OptionSet optionSet16 = optionParser2.parse(arr);
if (optionSet16.has(optionSpec9)) {
optionParser2.printHelpOn(System.err);
return;
}
final Path path17 = Paths.get("server.properties");
final DedicatedServerSettings wf18 = new DedicatedServerSettings(path17);
wf18.forceSave();
final Path path18 = Paths.get("eula.txt");
final Eula st20 = new Eula(path18);
if (optionSet16.has(optionSpec4)) {
MinecraftServer.LOGGER.info("Initialized '" + path17.toAbsolutePath().toString() + "' and '" + path18.toAbsolutePath().toString() + "'");
return;
}
if (!st20.hasAgreedToEULA()) {
MinecraftServer.LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
return;
}
Bootstrap.bootStrap();
Bootstrap.validate();
final String string21 = optionSet16.<String>valueOf(optionSpec11);
final YggdrasilAuthenticationService yggdrasilAuthenticationService22 = new YggdrasilAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString());
final MinecraftSessionService minecraftSessionService23 = yggdrasilAuthenticationService22.createMinecraftSessionService();
final GameProfileRepository gameProfileRepository24 = yggdrasilAuthenticationService22.createProfileRepository();
final GameProfileCache zk25 = new GameProfileCache(gameProfileRepository24, new File(string21, MinecraftServer.USERID_CACHE_FILE.getName()));
final String string22 = Optional.<String>ofNullable((String)optionSet16.<T>valueOf((OptionSpec<T>)optionSpec12)).orElse(wf18.getProperties().levelName);
final DedicatedServer wd27 = new DedicatedServer(new File(string21), wf18, DataFixers.getDataFixer(), yggdrasilAuthenticationService22, minecraftSessionService23, gameProfileRepository24, zk25, LoggerChunkProgressListener::new, string22);
wd27.setSingleplayerName(optionSet16.<String>valueOf(optionSpec10));
wd27.setPort(optionSet16.<Integer>valueOf(optionSpec13));
wd27.setDemo(optionSet16.has(optionSpec5));
wd27.setBonusChest(optionSet16.has(optionSpec6));
wd27.forceUpgrade(optionSet16.has(optionSpec7));
wd27.eraseCache(optionSet16.has(optionSpec8));
wd27.setId(optionSet16.<String>valueOf(optionSpec14));
final boolean boolean28 = !optionSet16.has(optionSpec3) && !optionSet16.<String>valuesOf(optionSpec15).contains("nogui");
if (boolean28 && !GraphicsEnvironment.isHeadless()) {
wd27.showGui();
}
wd27.forkAndRun();
final Thread thread29 = new Thread("Server Shutdown Thread") {
@Override
public void run() {
wd27.halt(true);
}
};
thread29.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(MinecraftServer.LOGGER));
Runtime.getRuntime().addShutdownHook(thread29);
}
catch (Exception exception16) {
MinecraftServer.LOGGER.fatal("Failed to start the minecraft server", (Throwable)exception16);
}
}
protected void setId(final String string) {
this.serverId = string;
}
protected void forceUpgrade(final boolean boolean1) {
this.forceUpgrade = boolean1;
}
protected void eraseCache(final boolean boolean1) {
this.eraseCache = boolean1;
}
public void forkAndRun() {
this.serverThread.start();
}
public boolean isShutdown() {
return !this.serverThread.isAlive();
}
public File getFile(final String string) {
return new File(this.getServerDirectory(), string);
}
public void info(final String string) {
MinecraftServer.LOGGER.info(string);
}
public void warn(final String string) {
MinecraftServer.LOGGER.warn(string);
}
public ServerLevel getLevel(final DimensionType cbf) {
return this.levels.get(cbf);
}
public Iterable<ServerLevel> getAllLevels() {
return this.levels.values();
}
public String getServerVersion() {
return SharedConstants.getCurrentVersion().getName();
}
public int getPlayerCount() {
return this.playerList.getPlayerCount();
}
public int getMaxPlayers() {
return this.playerList.getMaxPlayers();
}
public String[] getPlayerNames() {
return this.playerList.getPlayerNamesArray();
}
public boolean isDebugging() {
return false;
}
public void error(final String string) {
MinecraftServer.LOGGER.error(string);
}
public void debug(final String string) {
if (this.isDebugging()) {
MinecraftServer.LOGGER.info(string);
}
}
public String getServerModName() {
return "vanilla";
}
public CrashReport fillReport(final CrashReport h) {
if (this.playerList != null) {
h.getSystemDetails().setDetail("Player Count", () -> this.playerList.getPlayerCount() + " / " + this.playerList.getMaxPlayers() + "; " + this.playerList.getPlayers());
}
final StringBuilder stringBuilder2;
final Iterator<UnopenedPack> iterator;
UnopenedPack yt4;
h.getSystemDetails().setDetail("Data Packs", () -> {
stringBuilder2 = new StringBuilder();
this.packRepository.getSelected().iterator();
while (iterator.hasNext()) {
yt4 = iterator.next();
if (stringBuilder2.length() > 0) {
stringBuilder2.append(", ");
}
stringBuilder2.append(yt4.getId());
if (!yt4.getCompatibility().isCompatible()) {
stringBuilder2.append(" (incompatible)");
}
}
return stringBuilder2.toString();
});
if (this.serverId != null) {
h.getSystemDetails().setDetail("Server Id", () -> this.serverId);
}
return h;
}
public boolean isInitialized() {
return this.universe != null;
}
@Override
public void sendMessage(final Component lf) {
MinecraftServer.LOGGER.info(lf.getString());
}
public KeyPair getKeyPair() {
return this.keyPair;
}
public int getPort() {
return this.port;
}
public void setPort(final int integer) {
this.port = integer;
}
public String getSingleplayerName() {
return this.singleplayerName;
}
public void setSingleplayerName(final String string) {
this.singleplayerName = string;
}
public boolean isSingleplayer() {
return this.singleplayerName != null;
}
public String getLevelIdName() {
return this.levelIdName;
}
public void setLevelName(final String string) {
this.levelName = string;
}
public String getLevelName() {
return this.levelName;
}
public void setKeyPair(final KeyPair keyPair) {
this.keyPair = keyPair;
}
public void setDifficulty(final Difficulty ajf, final boolean boolean2) {
for (final ServerLevel xd5 : this.getAllLevels()) {
final LevelData crj6 = xd5.getLevelData();
if (!boolean2 && crj6.isDifficultyLocked()) {
continue;
}
if (crj6.isHardcore()) {
crj6.setDifficulty(Difficulty.HARD);
xd5.setSpawnSettings(true, true);
}
else if (this.isSingleplayer()) {
crj6.setDifficulty(ajf);
xd5.setSpawnSettings(xd5.getDifficulty() != Difficulty.PEACEFUL, true);
}
else {
crj6.setDifficulty(ajf);
xd5.setSpawnSettings(this.getSpawnMonsters(), this.animals);
}
}
this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate);
}
public void setDifficultyLocked(final boolean boolean1) {
for (final ServerLevel xd4 : this.getAllLevels()) {
final LevelData crj5 = xd4.getLevelData();
crj5.setDifficultyLocked(boolean1);
}
this.getPlayerList().getPlayers().forEach(this::sendDifficultyUpdate);
}
private void sendDifficultyUpdate(final ServerPlayer xe) {
final LevelData crj3 = xe.getLevel().getLevelData();
xe.connection.send(new ClientboundChangeDifficultyPacket(crj3.getDifficulty(), crj3.isDifficultyLocked()));
}
protected boolean getSpawnMonsters() {
return true;
}
public boolean isDemo() {
return this.isDemo;
}
public void setDemo(final boolean boolean1) {
this.isDemo = boolean1;
}
public void setBonusChest(final boolean boolean1) {
this.levelHasStartingBonusChest = boolean1;
}
public LevelStorageSource getStorageSource() {
return this.storageSource;
}
public String getResourcePack() {
return this.resourcePack;
}
public String getResourcePackHash() {
return this.resourcePackHash;
}
public void setResourcePack(final String string1, final String string2) {
this.resourcePack = string1;
this.resourcePackHash = string2;
}
@Override
public void populateSnooper(final Snooper ajp) {
ajp.setDynamicData("whitelist_enabled", false);
ajp.setDynamicData("whitelist_count", 0);
if (this.playerList != null) {
ajp.setDynamicData("players_current", this.getPlayerCount());
ajp.setDynamicData("players_max", this.getMaxPlayers());
ajp.setDynamicData("players_seen", this.getLevel(DimensionType.OVERWORLD).getLevelStorage().getSeenPlayers().length);
}
ajp.setDynamicData("uses_auth", this.onlineMode);
ajp.setDynamicData("gui_state", this.hasGui() ? "enabled" : "disabled");
ajp.setDynamicData("run_time", (Util.getMillis() - ajp.getStartupTime()) / 60L * 1000L);
ajp.setDynamicData("avg_tick_ms", (int)(Mth.average(this.tickTimes) * 1.0E-6));
int integer3 = 0;
for (final ServerLevel xd5 : this.getAllLevels()) {
if (xd5 != null) {
final LevelData crj6 = xd5.getLevelData();
ajp.setDynamicData("world[" + integer3 + "][dimension]", xd5.dimension.getType());
ajp.setDynamicData("world[" + integer3 + "][mode]", crj6.getGameType());
ajp.setDynamicData("world[" + integer3 + "][difficulty]", xd5.getDifficulty());
ajp.setDynamicData("world[" + integer3 + "][hardcore]", crj6.isHardcore());
ajp.setDynamicData("world[" + integer3 + "][generator_name]", crj6.getGeneratorType().getName());
ajp.setDynamicData("world[" + integer3 + "][generator_version]", crj6.getGeneratorType().getVersion());
ajp.setDynamicData("world[" + integer3 + "][height]", this.maxBuildHeight);
ajp.setDynamicData("world[" + integer3 + "][chunks_loaded]", xd5.getChunkSource().getLoadedChunksCount());
++integer3;
}
}
ajp.setDynamicData("worlds", integer3);
}
public abstract boolean isDedicatedServer();
public boolean usesAuthentication() {
return this.onlineMode;
}
public void setUsesAuthentication(final boolean boolean1) {
this.onlineMode = boolean1;
}
public boolean getPreventProxyConnections() {
return this.preventProxyConnections;
}
public void setPreventProxyConnections(final boolean boolean1) {
this.preventProxyConnections = boolean1;
}
public boolean isAnimals() {
return this.animals;
}
public void setAnimals(final boolean boolean1) {
this.animals = boolean1;
}
public boolean isNpcsEnabled() {
return this.npcs;
}
public abstract boolean isEpollEnabled();
public void setNpcsEnabled(final boolean boolean1) {
this.npcs = boolean1;
}
public boolean isPvpAllowed() {
return this.pvp;
}
public void setPvpAllowed(final boolean boolean1) {
this.pvp = boolean1;
}
public boolean isFlightAllowed() {
return this.allowFlight;
}
public void setFlightAllowed(final boolean boolean1) {
this.allowFlight = boolean1;
}
public abstract boolean isCommandBlockEnabled();
public String getMotd() {
return this.motd;
}
public void setMotd(final String string) {
this.motd = string;
}
public int getMaxBuildHeight() {
return this.maxBuildHeight;
}
public void setMaxBuildHeight(final int integer) {
this.maxBuildHeight = integer;
}
public boolean isStopped() {
return this.stopped;
}
public PlayerList getPlayerList() {
return this.playerList;
}
public void setPlayerList(final PlayerList zo) {
this.playerList = zo;
}
public abstract boolean isPublished();
public void setDefaultGameMode(final GameType bjq) {
for (final ServerLevel xd4 : this.getAllLevels()) {
xd4.getLevelData().setGameType(bjq);
}
}
@Nullable
public ServerConnectionListener getConnection() {
return this.connection;
}
public boolean isReady() {
return this.isReady;
}
public boolean hasGui() {
return false;
}
public abstract boolean publishServer(final GameType bjq, final boolean boolean2, final int integer);
public int getTickCount() {
return this.tickCount;
}
public void delayStartProfiler() {
this.delayProfilerStart = true;
}
public Snooper getSnooper() {
return this.snooper;
}
public int getSpawnProtectionRadius() {
return 16;
}
public boolean isUnderSpawnProtection(final Level bjt, final BlockPos fk, final Player ayg) {
return false;
}
public void setForceGameType(final boolean boolean1) {
this.forceGameType = boolean1;
}
public boolean getForceGameType() {
return this.forceGameType;
}
public int getPlayerIdleTimeout() {
return this.playerIdleTimeout;
}
public void setPlayerIdleTimeout(final int integer) {
this.playerIdleTimeout = integer;
}
public MinecraftSessionService getSessionService() {
return this.sessionService;
}
public GameProfileRepository getProfileRepository() {
return this.profileRepository;
}
public GameProfileCache getProfileCache() {
return this.profileCache;
}
public ServerStatus getStatus() {
return this.status;
}
public void invalidateStatus() {
this.lastServerStatus = 0L;
}
public int getAbsoluteMaxWorldSize() {
return 29999984;
}
public boolean scheduleExecutables() {
return super.scheduleExecutables() && !this.isStopped();
}
public Thread getRunningThread() {
return this.serverThread;
}
public int getCompressionThreshold() {
return 256;
}
public long getNextTickTime() {
return this.nextTickTime;
}
public DataFixer getFixerUpper() {
return this.fixerUpper;
}
public int getSpawnRadius(@Nullable final ServerLevel xd) {
if (xd != null) {
return xd.getGameRules().getInt(GameRules.RULE_SPAWN_RADIUS);
}
return 10;
}
public ServerAdvancementManager getAdvancements() {
return this.advancements;
}
public ServerFunctionManager getFunctions() {
return this.functions;
}
public void reloadResources() {
if (!this.isSameThread()) {
this.execute(this::reloadResources);
return;
}
this.getPlayerList().saveAll();
this.packRepository.reload();
this.updateSelectedPacks(this.getLevel(DimensionType.OVERWORLD).getLevelData());
this.getPlayerList().reloadResources();
this.refreshRegistries();
}
private void updateSelectedPacks(final LevelData crj) {
final List<UnopenedPack> list3 = Lists.newArrayList(this.packRepository.getSelected());
for (final UnopenedPack yt2 : this.packRepository.getAvailable()) {
if (!crj.getDisabledDataPacks().contains(yt2.getId()) && !list3.contains(yt2)) {
MinecraftServer.LOGGER.info("Found new data pack {}, loading it automatically", yt2.getId());
yt2.getDefaultPosition().<UnopenedPack, UnopenedPack>insert(list3, yt2, yt -> yt, false);
}
}
this.packRepository.setSelected(list3);
final List<Pack> list4 = Lists.newArrayList();
this.packRepository.getSelected().forEach(yt -> list4.add(yt.open()));
final CompletableFuture<Unit> completableFuture5 = this.resources.reload(this.executor, this, list4, MinecraftServer.DATA_RELOAD_INITIAL_TASK);
this.managedBlock(completableFuture5::isDone);
try {
completableFuture5.get();
}
catch (Exception exception6) {
MinecraftServer.LOGGER.error("Failed to reload data packs", (Throwable)exception6);
}
crj.getEnabledDataPacks().clear();
crj.getDisabledDataPacks().clear();
this.packRepository.getSelected().forEach(yt -> crj.getEnabledDataPacks().add(yt.getId()));
this.packRepository.getAvailable().forEach(yt -> {
if (!this.packRepository.getSelected().contains(yt)) {
crj.getDisabledDataPacks().add(yt.getId());
}
});
}
public void kickUnlistedPlayers(final CommandSourceStack cq) {
if (!this.isEnforceWhitelist()) {
return;
}
final PlayerList zo3 = cq.getServer().getPlayerList();
final UserWhiteList zv4 = zo3.getWhiteList();
if (!zv4.isEnabled()) {
return;
}
final List<ServerPlayer> list5 = Lists.newArrayList(zo3.getPlayers());
for (final ServerPlayer xe7 : list5) {
if (!zv4.isWhiteListed(xe7.getGameProfile())) {
xe7.connection.disconnect(new TranslatableComponent("multiplayer.disconnect.not_whitelisted", new Object[0]));
}
}
}
public ReloadableResourceManager getResources() {
return this.resources;
}
public PackRepository<UnopenedPack> getPackRepository() {
return this.packRepository;
}
public Commands getCommands() {
return this.commands;
}
public CommandSourceStack createCommandSourceStack() {
return new CommandSourceStack(this, (this.getLevel(DimensionType.OVERWORLD) == null) ? Vec3.ZERO : new Vec3(this.getLevel(DimensionType.OVERWORLD).getSharedSpawnPos()), Vec2.ZERO, this.getLevel(DimensionType.OVERWORLD), 4, "Server", new TextComponent("Server"), this, null);
}
@Override
public boolean acceptsSuccess() {
return true;
}
@Override
public boolean acceptsFailure() {
return true;
}
public RecipeManager getRecipeManager() {
return this.recipes;
}
public TagManager getTags() {
return this.tags;
}
public ServerScoreboard getScoreboard() {
return this.scoreboard;
}
public CommandStorage getCommandStorage() {
if (this.commandStorage == null) {
throw new NullPointerException("Called before server init");
}
return this.commandStorage;
}
public LootTables getLootTables() {
return this.lootTables;
}
public PredicateManager getPredicateManager() {
return this.predicateManager;
}
public GameRules getGameRules() {
return this.getLevel(DimensionType.OVERWORLD).getGameRules();
}
public CustomBossEvents getCustomBossEvents() {
return this.customBossEvents;
}
public boolean isEnforceWhitelist() {
return this.enforceWhitelist;
}
public void setEnforceWhitelist(final boolean boolean1) {
this.enforceWhitelist = boolean1;
}
public float getAverageTickTime() {
return this.averageTickTime;
}
public int getProfilePermissions(final GameProfile gameProfile) {
if (!this.getPlayerList().isOp(gameProfile)) {
return 0;
}
final ServerOpListEntry zq3 = this.getPlayerList().getOps().get(gameProfile);
if (zq3 != null) {
return zq3.getLevel();
}
if (this.isSingleplayerOwner(gameProfile)) {
return 4;
}
if (this.isSingleplayer()) {
return this.getPlayerList().isAllowCheatsForAllPlayers() ? 4 : 0;
}
return this.getOperatorUserPermissionLevel();
}
public FrameTimer getFrameTimer() {
return this.frameTimer;
}
public GameProfiler getProfiler() {
return this.profiler;
}
public Executor getBackgroundTaskExecutor() {
return this.executor;
}
public abstract boolean isSingleplayerOwner(final GameProfile gameProfile);
public void saveDebugReport(final Path path) throws IOException {
final Path path2 = path.resolve("levels");
for (final Map.Entry<DimensionType, ServerLevel> entry5 : this.levels.entrySet()) {
final ResourceLocation sm6 = DimensionType.getName(entry5.getKey());
final Path path3 = path2.resolve(sm6.getNamespace()).resolve(sm6.getPath());
Files.createDirectories(path3, new FileAttribute[0]);
entry5.getValue().saveDebugReport(path3);
}
this.dumpGameRules(path.resolve("gamerules.txt"));
this.dumpClasspath(path.resolve("classpath.txt"));
this.dumpCrashCategory(path.resolve("example_crash.txt"));
this.dumpMiscStats(path.resolve("stats.txt"));
this.dumpThreads(path.resolve("threads.txt"));
}
private void dumpMiscStats(final Path path) throws IOException {
try (final Writer writer3 = Files.newBufferedWriter(path)) {
writer3.write(String.format("pending_tasks: %d\n", this.getPendingTasksCount()));
writer3.write(String.format("average_tick_time: %f\n", this.getAverageTickTime()));
writer3.write(String.format("tick_times: %s\n", Arrays.toString(this.tickTimes)));
writer3.write(String.format("queue: %s\n", Util.backgroundExecutor()));
}
}
private void dumpCrashCategory(final Path path) throws IOException {
final CrashReport h3 = new CrashReport("Server dump", new Exception("dummy"));
this.fillReport(h3);
try (final Writer writer4 = Files.newBufferedWriter(path)) {
writer4.write(h3.getFriendlyReport());
}
}
private void dumpGameRules(final Path path) throws IOException {
try (final Writer writer3 = Files.newBufferedWriter(path)) {
final List<String> list5 = Lists.newArrayList();
final GameRules bjp6 = this.getGameRules();
GameRules.visitGameRuleTypes(new GameRules.GameRuleTypeVisitor() {
@Override
public <T extends GameRules.Value<T>> void visit(final GameRules.Key<T> d, final GameRules.Type<T> e) {
list5.add(String.format("%s=%s\n", d.getId(), bjp6.<T>getRule(d).toString()));
}
});
for (final String string8 : list5) {
writer3.write(string8);
}
}
}
private void dumpClasspath(final Path path) throws IOException {
try (final Writer writer3 = Files.newBufferedWriter(path)) {
final String string5 = System.getProperty("java.class.path");
final String string6 = System.getProperty("path.separator");
for (final String string7 : Splitter.on(string6).split(string5)) {
writer3.write(string7);
writer3.write("\n");
}
}
}
private void dumpThreads(final Path path) throws IOException {
final ThreadMXBean threadMXBean3 = ManagementFactory.getThreadMXBean();
final ThreadInfo[] arr4 = threadMXBean3.dumpAllThreads(true, true);
Arrays.<ThreadInfo>sort(arr4, Comparator.comparing(ThreadInfo::getThreadName));
try (final Writer writer5 = Files.newBufferedWriter(path)) {
for (final ThreadInfo threadInfo10 : arr4) {
writer5.write(threadInfo10.toString());
writer5.write(10);
}
}
}
private void refreshRegistries() {
Block.BLOCK_STATE_REGISTRY.forEach(BlockState::initCache);
}
static {
LOGGER = LogManager.getLogger();
USERID_CACHE_FILE = new File("usercache.json");
DATA_RELOAD_INITIAL_TASK = CompletableFuture.<Unit>completedFuture(Unit.INSTANCE);
DEMO_SETTINGS = new LevelSettings("North Carolina".hashCode(), GameType.SURVIVAL, true, false, LevelType.NORMAL).enableStartingBonusItems();
}
}