io.github.m0pt0pmatt.survivalgames.command.executor.DemoCommand.java Source code

Java tutorial

Introduction

Here is the source code for io.github.m0pt0pmatt.survivalgames.command.executor.DemoCommand.java

Source

/*
 * This file is part of SurvivalGames, licensed under the MIT License (MIT).
 *
 * Copyright (c) Matthew Broomfield <m0pt0pmatt17@gmail.com>
 * Copyright (c) contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package io.github.m0pt0pmatt.survivalgames.command.executor;

import com.google.common.io.MoreFiles;
import com.google.common.io.RecursiveDeleteOption;
import io.github.m0pt0pmatt.survivalgames.SurvivalGamesPlugin;
import io.github.m0pt0pmatt.survivalgames.command.CommandKeys;
import io.github.m0pt0pmatt.survivalgames.command.executor.set.SetBlocksCommand;
import io.github.m0pt0pmatt.survivalgames.game.SurvivalGameRepository;
import io.github.m0pt0pmatt.survivalgames.thread.ProgressBuilder;
import io.github.m0pt0pmatt.survivalgames.thread.UnzipRunnable;
import io.github.m0pt0pmatt.survivalgames.thread.UrlDownloadRunnable;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandException;
import org.spongepowered.api.command.CommandResult;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.command.args.CommandContext;
import org.spongepowered.api.command.args.GenericArguments;
import org.spongepowered.api.text.Text;
import org.spongepowered.api.world.DimensionTypes;
import org.spongepowered.api.world.World;
import org.spongepowered.api.world.WorldArchetype;
import org.spongepowered.api.world.storage.WorldProperties;

import javax.annotation.Nonnull;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAmount;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import static io.github.m0pt0pmatt.survivalgames.Util.sendSuccess;

public class DemoCommand extends LeafCommand {

    private static final DemoCommand INSTANCE = new DemoCommand();

    private static final String DEMO_MAP_OBJECT = "ssg-demo-map_v4.zip";

    private static final String DEMO_MAP_WORLD_NAME = "ssg-demo-map";

    private static final String S3_BUCKET = "https://s3.amazonaws.com/com.cloudcraftnetwork.survivalgames.maps/";

    private DemoCommand() {
        super(RootCommand.getInstance(), "demo", GenericArguments.none());
    }

    @Override
    @Nonnull
    public CommandResult executeCommand(@Nonnull CommandSource src, @Nonnull CommandContext args)
            throws CommandException {

        URL url;
        try {
            url = new URL(S3_BUCKET + DEMO_MAP_OBJECT);
        } catch (MalformedURLException e) {
            throw new CommandException(Text.of("Bad url"), e);
        }

        UrlDownloadRunnable urlDownloadRunnable = new UrlDownloadRunnable(url, DEMO_MAP_OBJECT, 25657717);
        TemporalAmount timeout = Duration.of(5, ChronoUnit.MINUTES);

        ProgressBuilder.builder(src, SurvivalGamesPlugin.SYNC_EXECUTOR, SurvivalGamesPlugin.ASYNC_EXECUTOR)
                .runSync(this::deleteExistingWorld, "Deleting Old World", timeout)
                .runAsync(urlDownloadRunnable, "Downloading World", timeout)
                .runAsync(this::unzipWorld, "Unzipping World", timeout)
                .runSync(this::loadWorld, "Loading World", timeout)
                .runSync(this::downloadConfig, "Downloading Config", timeout)
                .runSync(() -> loadConfig(src), "Loading Config", timeout)
                .runSync(() -> setBlocks(src), "Setting Blocks", timeout)
                .runAsync(this::downloadSchedule, "Downloading Schedule", timeout)
                .runSync(() -> scheduleGame(src), "Scheduling Game", timeout)
                .runSync(() -> sendSuccess(src, "Demo ready! Join with /ssg join demo"), "", timeout).start();

        return CommandResult.success();
    }

    private void deleteExistingWorld() {

        Optional<World> world = Sponge.getServer().getWorld(DEMO_MAP_WORLD_NAME);
        if (world.isPresent()) {
            World w = world.get();
            if (!Sponge.getServer().unloadWorld(w)) {
                throw new RuntimeException("Could not unload demo world");
            }
        }

        Optional<WorldProperties> worldProperties = Sponge.getServer().getWorldProperties(DEMO_MAP_WORLD_NAME);
        if (worldProperties.isPresent()) {
            WorldProperties wp = worldProperties.get();
            CompletableFuture<Boolean> future = Sponge.getServer().deleteWorld(wp);
            try {
                if (!future.get(60, TimeUnit.SECONDS)) {
                    throw new RuntimeException("Could not delete demo world");
                }
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception e) {
                throw new RuntimeException("Could not delete demo world");
            }
        }
    }

    private void unzipWorld() {
        File existing = new File(Sponge.getServer().getDefaultWorldName(), DEMO_MAP_WORLD_NAME);
        if (existing.exists()) {
            try {
                MoreFiles.deleteRecursively(existing.toPath(), RecursiveDeleteOption.ALLOW_INSECURE);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        new UnzipRunnable(DEMO_MAP_OBJECT, Sponge.getServer().getDefaultWorldName()).run();
    }

    private void loadWorld() {
        try {
            WorldProperties props = Sponge.getServer().createWorldProperties(DEMO_MAP_WORLD_NAME,
                    WorldArchetype.builder().dimension(DimensionTypes.OVERWORLD).enabled(true).pvp(true)
                            .build(UUID.randomUUID().toString(), DEMO_MAP_WORLD_NAME));

            if (!Sponge.getServer().loadWorld(props).isPresent()) {
                throw new RuntimeException("Could not load world, check logs");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void downloadConfig() {
        try {
            ReadableByteChannel readableByteChannel = Channels
                    .newChannel(new URL(S3_BUCKET + "demo.yml").openStream());
            FileOutputStream fileOutputStream = new FileOutputStream(
                    "config" + File.separator + "survival-games" + File.separator + "demo.yml");
            fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
            fileOutputStream.close();
        } catch (Exception e) {
            throw new RuntimeException("Unable to download config", e);
        }
    }

    private void loadConfig(CommandSource src) {
        CommandContext loadContext = new CommandContext();
        loadContext.putArg(CommandKeys.SURVIVAL_GAME_NAME, "demo");
        loadContext.putArg(CommandKeys.FILE_PATH,
                new File("config" + File.separator + "survival-games" + File.separator + "demo.yml").toPath());

        try {
            LoadConfigCommand.getInstance().execute(src, loadContext);
        } catch (CommandException e) {
            throw new RuntimeException(e);
        }
    }

    private void setBlocks(CommandSource src) {
        CommandContext context = new CommandContext();
        context.putArg(CommandKeys.SURVIVAL_GAME, SurvivalGameRepository.get("demo")
                .orElseThrow(() -> new RuntimeException("Demo map didn't exist")));

        try {
            SetBlocksCommand.getInstance().execute(src, context);
        } catch (CommandException e) {
            throw new RuntimeException(e);
        }
    }

    private void downloadSchedule() {
        try {
            ReadableByteChannel readableByteChannel = Channels
                    .newChannel(new URL(S3_BUCKET + "demo-schedule.yml").openStream());
            FileOutputStream fileOutputStream = new FileOutputStream(
                    "config" + File.separator + "survival-games" + File.separator + "demo-schedule.yml");
            fileOutputStream.getChannel().transferFrom(readableByteChannel, 0, Long.MAX_VALUE);
            fileOutputStream.close();
        } catch (Exception e) {
            throw new RuntimeException("Unable to download config", e);
        }
    }

    private void scheduleGame(CommandSource src) {
        CommandContext context = new CommandContext();
        context.putArg(CommandKeys.SURVIVAL_GAME, SurvivalGameRepository.get("demo")
                .orElseThrow(() -> new RuntimeException("Demo map didn't exist")));

        context.putArg(CommandKeys.FILE_PATH,
                new File("config" + File.separator + "survival-games" + File.separator + "demo-schedule.yml")
                        .toPath());

        try {
            ScheduleCommand.getInstance().execute(src, context);
        } catch (CommandException e) {
            throw new RuntimeException(e);
        }
    }

    public static DemoCommand getInstance() {
        return INSTANCE;
    }
}