package net.minecraft.server;

import org.apache.logging.log4j.LogManager;
import net.minecraft.network.chat.Component;
import net.minecraft.util.Mth;
import net.minecraft.util.worldupdate.WorldUpgrader;
import net.minecraft.world.level.Level;
import net.minecraft.resources.ResourceKey;
import com.google.common.collect.ImmutableSet;
import java.util.function.BooleanSupplier;
import com.mojang.datafixers.DataFixer;
import net.minecraft.server.dedicated.DedicatedServerProperties;
import net.minecraft.world.level.storage.WorldData;
import java.util.concurrent.CompletableFuture;
import com.mojang.authlib.GameProfileRepository;
import com.mojang.authlib.minecraft.MinecraftSessionService;
import java.nio.file.Path;
import joptsimple.OptionSet;
import net.minecraft.DefaultUncaughtExceptionHandler;
import java.awt.GraphicsEnvironment;
import net.minecraft.server.level.progress.LoggerChunkProgressListener;
import net.minecraft.server.dedicated.DedicatedServer;
import net.minecraft.util.datafix.DataFixers;
import net.minecraft.world.level.storage.PrimaryLevelData;
import com.mojang.serialization.Lifecycle;
import net.minecraft.world.level.LevelSettings;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.levelgen.WorldGenSettings;
import com.mojang.serialization.DynamicOps;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.RegistryReadOps;
import net.minecraft.nbt.NbtOps;
import net.minecraft.core.RegistryAccess;
import net.minecraft.commands.Commands;
import net.minecraft.world.level.DataPackConfig;
import net.minecraft.server.packs.repository.PackRepository;
import net.minecraft.server.packs.repository.FolderRepositorySource;
import net.minecraft.server.packs.repository.PackSource;
import net.minecraft.world.level.storage.LevelResource;
import net.minecraft.server.packs.repository.ServerPacksSource;
import net.minecraft.server.packs.repository.RepositorySource;
import net.minecraft.server.packs.repository.Pack;
import net.minecraft.world.level.storage.LevelStorageSource;
import java.util.Optional;
import net.minecraft.server.players.GameProfileCache;
import com.mojang.authlib.yggdrasil.YggdrasilAuthenticationService;
import java.util.UUID;
import java.net.Proxy;
import java.io.File;
import net.minecraft.server.dedicated.DedicatedServerSettings;
import java.nio.file.Paths;
import net.minecraft.Util;
import net.minecraft.CrashReport;
import java.io.OutputStream;
import joptsimple.OptionSpec;
import joptsimple.OptionParser;
import org.apache.logging.log4j.Logger;

public class Main {
    private static final Logger LOGGER;
    
    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("safeMode", "Loads level with vanilla datapack only");
        final OptionSpec<Void> optionSpec10 = optionParser2.accepts("help").forHelp();
        final OptionSpec<String> optionSpec11 = optionParser2.accepts("singleplayer").withRequiredArg();
        final OptionSpec<String> optionSpec12 = optionParser2.accepts("universe").withRequiredArg().defaultsTo(".", new String[0]);
        final OptionSpec<String> optionSpec13 = optionParser2.accepts("world").withRequiredArg();
        final OptionSpec<Integer> optionSpec14 = optionParser2.accepts("port").withRequiredArg().<Integer>ofType(Integer.class).defaultsTo(-1, new Integer[0]);
        final OptionSpec<String> optionSpec15 = optionParser2.accepts("serverId").withRequiredArg();
        final OptionSpec<String> optionSpec16 = optionParser2.nonOptions();
        try {
            final OptionSet optionSet17 = optionParser2.parse(arr);
            if (optionSet17.has(optionSpec10)) {
                optionParser2.printHelpOn(System.err);
                return;
            }
            CrashReport.preload();
            Bootstrap.bootStrap();
            Bootstrap.validate();
            Util.startTimerHackThread();
            final Path path18 = Paths.get("server.properties");
            final DedicatedServerSettings yf19 = new DedicatedServerSettings(path18);
            yf19.forceSave();
            final Path path19 = Paths.get("eula.txt");
            final Eula uo21 = new Eula(path19);
            if (optionSet17.has(optionSpec4)) {
                Main.LOGGER.info("Initialized '{}' and '{}'", path18.toAbsolutePath(), path19.toAbsolutePath());
                return;
            }
            if (!uo21.hasAgreedToEULA()) {
                Main.LOGGER.info("You need to agree to the EULA in order to run the server. Go to eula.txt for more info.");
                return;
            }
            final File file22 = new File(optionSet17.<String>valueOf(optionSpec12));
            final YggdrasilAuthenticationService yggdrasilAuthenticationService23 = new YggdrasilAuthenticationService(Proxy.NO_PROXY, UUID.randomUUID().toString());
            final MinecraftSessionService minecraftSessionService24 = yggdrasilAuthenticationService23.createMinecraftSessionService();
            final GameProfileRepository gameProfileRepository25 = yggdrasilAuthenticationService23.createProfileRepository();
            final GameProfileCache abl26 = new GameProfileCache(gameProfileRepository25, new File(file22, MinecraftServer.USERID_CACHE_FILE.getName()));
            final String string27 = Optional.<String>ofNullable((String)optionSet17.<T>valueOf((OptionSpec<T>)optionSpec13)).orElse(yf19.getProperties().levelName);
            final LevelStorageSource dae28 = LevelStorageSource.createDefault(file22.toPath());
            final LevelStorageSource.LevelStorageAccess a29 = dae28.createAccess(string27);
            MinecraftServer.convertFromRegionFormatIfNeeded(a29);
            final DataPackConfig bpn30 = a29.getDataPacks();
            final boolean boolean31 = optionSet17.has(optionSpec9);
            if (boolean31) {
                Main.LOGGER.warn("Safe mode active, only vanilla datapack will be loaded");
            }
            final PackRepository<Pack> aar32 = new PackRepository<Pack>(Pack::new, new RepositorySource[] { new ServerPacksSource(), new FolderRepositorySource(a29.getLevelPath(LevelResource.DATAPACK_DIR).toFile(), PackSource.WORLD) });
            final DataPackConfig bpn31 = MinecraftServer.configurePackRepository(aar32, (bpn30 == null) ? DataPackConfig.DEFAULT : bpn30, boolean31);
            final CompletableFuture<ServerResources> completableFuture34 = ServerResources.loadResources(aar32.openAllSelected(), Commands.CommandSelection.DEDICATED, yf19.getProperties().functionPermissionLevel, Util.backgroundExecutor(), Runnable::run);
            ServerResources uw35;
            try {
                uw35 = completableFuture34.get();
            }
            catch (Exception exception36) {
                Main.LOGGER.warn("Failed to load datapacks, can't proceed with server load. You can either fix your datapacks or reset to vanilla with --safeMode", (Throwable)exception36);
                aar32.close();
                return;
            }
            uw35.updateGlobals();
            final RegistryAccess.RegistryHolder a30 = RegistryAccess.builtin();
            final RegistryReadOps<Tag> ue37 = RegistryReadOps.<Tag>create((com.mojang.serialization.DynamicOps<Tag>)NbtOps.INSTANCE, uw35.getResourceManager(), a30);
            WorldData dal38 = a29.getDataTag((DynamicOps<Tag>)ue37, bpn31);
            if (dal38 == null) {
                LevelSettings bqe39;
                WorldGenSettings cix40;
                if (optionSet17.has(optionSpec5)) {
                    bqe39 = MinecraftServer.DEMO_SETTINGS;
                    cix40 = WorldGenSettings.DEMO_SETTINGS;
                }
                else {
                    final DedicatedServerProperties ye41 = yf19.getProperties();
                    bqe39 = new LevelSettings(ye41.levelName, ye41.gamemode, ye41.hardcore, ye41.difficulty, false, new GameRules(), bpn31);
                    cix40 = (optionSet17.has(optionSpec6) ? ye41.worldGenSettings.withBonusChest() : ye41.worldGenSettings);
                }
                dal38 = new PrimaryLevelData(bqe39, cix40, Lifecycle.stable());
            }
            if (optionSet17.has(optionSpec7)) {
                forceUpgrade(a29, DataFixers.getDataFixer(), optionSet17.has(optionSpec8), () -> true, dal38.worldGenSettings().levels());
            }
            a29.saveDataTag(a30, dal38);
            final WorldData dal39 = dal38;
            final RegistryAccess.RegistryHolder a31;
            final LevelStorageSource.LevelStorageAccess a32;
            final PackRepository<Pack> aar33;
            final ServerResources uw36;
            final WorldData dal40;
            final DedicatedServerSettings yf20;
            final MinecraftSessionService minecraftSessionService25;
            final GameProfileRepository gameProfileRepository26;
            final GameProfileCache abl27;
            final DedicatedServer yd41;
            final OptionSet set;
            final OptionSpec<String> option;
            final OptionSpec<Integer> option2;
            final OptionSpec<?> option3;
            final OptionSpec<String> option4;
            final OptionSpec<?> option5;
            final OptionSpec<Object> option6;
            final boolean boolean32;
            final DedicatedServer yd40 = MinecraftServer.<DedicatedServer>spin(thread -> {
                yd41 = new DedicatedServer(thread, a31, a32, aar33, uw36, dal40, yf20, DataFixers.getDataFixer(), minecraftSessionService25, gameProfileRepository26, abl27, LoggerChunkProgressListener::new);
                yd41.setSingleplayerName(set.<String>valueOf(option));
                yd41.setPort(set.<Integer>valueOf(option2));
                yd41.setDemo(set.has(option3));
                yd41.setId(set.<String>valueOf(option4));
                boolean32 = (!set.has(option5) && !set.valuesOf(option6).contains("nogui"));
                if (boolean32 && !GraphicsEnvironment.isHeadless()) {
                    yd41.showGui();
                }
                return yd41;
            });
            final Thread thread2 = new Thread("Server Shutdown Thread") {
                @Override
                public void run() {
                    yd40.halt(true);
                }
            };
            thread2.setUncaughtExceptionHandler(new DefaultUncaughtExceptionHandler(Main.LOGGER));
            Runtime.getRuntime().addShutdownHook(thread2);
        }
        catch (Exception exception37) {
            Main.LOGGER.fatal("Failed to start the minecraft server", (Throwable)exception37);
        }
    }
    
    private static void forceUpgrade(final LevelStorageSource.LevelStorageAccess a, final DataFixer dataFixer, final boolean boolean3, final BooleanSupplier booleanSupplier, final ImmutableSet<ResourceKey<Level>> immutableSet) {
        Main.LOGGER.info("Forcing world upgrade!");
        final WorldUpgrader amu6 = new WorldUpgrader(a, dataFixer, immutableSet, boolean3);
        Component mr7 = null;
        while (!amu6.isFinished()) {
            final Component mr8 = amu6.getStatus();
            if (mr7 != mr8) {
                mr7 = mr8;
                Main.LOGGER.info(amu6.getStatus().getString());
            }
            final int integer9 = amu6.getTotalChunks();
            if (integer9 > 0) {
                final int integer10 = amu6.getConverted() + amu6.getSkipped();
                Main.LOGGER.info("{}% completed ({} / {} chunks)...", Mth.floor(integer10 / (float)integer9 * 100.0f), integer10, integer9);
            }
            if (!booleanSupplier.getAsBoolean()) {
                amu6.cancel();
            }
            else {
                try {
                    Thread.sleep(1000L);
                }
                catch (InterruptedException ex) {}
            }
        }
    }
    
    static {
        LOGGER = LogManager.getLogger();
    }
}
