com.kegare.caveworld.world.WorldProviderCaveworld.java Source code

Java tutorial

Introduction

Here is the source code for com.kegare.caveworld.world.WorldProviderCaveworld.java

Source

/*
 * Caveworld
 *
 * Copyright (c) 2014 kegare
 * https://github.com/kegare
 *
 * This mod is distributed under the terms of the Minecraft Mod Public License Japanese Translation, or MMPL_J.
 */

package com.kegare.caveworld.world;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.nio.file.Files;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Comparator;
import java.util.Set;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.regex.Pattern;

import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraft.event.ClickEvent;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChunkCoordinates;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.util.IChatComponent;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;
import net.minecraft.util.Vec3;
import net.minecraft.world.WorldProviderSurface;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldType;
import net.minecraft.world.chunk.Chunk;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.structure.MapGenStructureIO;
import net.minecraftforge.client.IRenderHandler;
import net.minecraftforge.common.DimensionManager;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.world.WorldEvent;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.logging.log4j.Level;

import com.bioxx.tfc.Core.TFC_Climate;
import com.bioxx.tfc.Core.TFC_Core;
import com.bioxx.tfc.WorldGen.WorldCacheManager;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import com.kegare.caveworld.api.CaveworldAPI;
import com.kegare.caveworld.block.CaveBlocks;
import com.kegare.caveworld.client.renderer.EmptyRenderer;
import com.kegare.caveworld.core.Caveworld;
import com.kegare.caveworld.core.Config;
import com.kegare.caveworld.handler.TFCCaveEventHooks;
import com.kegare.caveworld.network.CaveSoundMessage;
import com.kegare.caveworld.network.RegenerateMessage;
import com.kegare.caveworld.util.CaveLog;
import com.kegare.caveworld.util.CaveUtils;
import com.kegare.caveworld.world.gen.MapGenStrongholdCaveworld;
import com.kegare.caveworld.world.gen.StructureStrongholdPiecesCaveworld;

import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.Optional.Method;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;

public class WorldProviderCaveworld extends WorldProviderSurface {
    private static NBTTagCompound dimData;

    private static long dimensionSeed;
    private static int subsurfaceHeight;

    public static ChunkCoordinates recentTeleportPos;

    public static NBTTagCompound getDimData() {
        if (dimData == null) {
            dimData = readDimData();
        }

        return dimData;
    }

    public static File getDimDir() {
        File root = DimensionManager.getCurrentSaveRootDirectory();

        if (root == null || !root.exists() || root.isFile()) {
            return null;
        }

        File dir = new File(root, new WorldProviderCaveworld().getSaveFolder());

        if (!dir.exists()) {
            dir.mkdirs();
        }

        return dir.isDirectory() ? dir : null;
    }

    private static NBTTagCompound readDimData() {
        NBTTagCompound data;
        File dir = getDimDir();

        if (dir == null) {
            data = null;
        } else {
            File file = new File(dir, "caveworld.dat");

            if (!file.exists() || !file.isFile() || !file.canRead()) {
                data = null;
            } else
                try (FileInputStream input = new FileInputStream(file)) {
                    data = CompressedStreamTools.readCompressed(input);
                } catch (Exception e) {
                    CaveLog.log(Level.ERROR, e, "An error occurred trying to reading Caveworld dimension data");

                    data = null;
                }
        }

        return data == null ? new NBTTagCompound() : data;
    }

    private static void writeDimData() {
        File dir = getDimDir();

        if (dir == null) {
            return;
        }

        try (FileOutputStream output = new FileOutputStream(new File(dir, "caveworld.dat"))) {
            NBTTagCompound data = getDimData();

            if (recentTeleportPos != null) {
                NBTTagCompound dat = new NBTTagCompound();

                dat.setInteger("PosX", recentTeleportPos.posX);
                dat.setInteger("PosY", recentTeleportPos.posY);
                dat.setInteger("PosZ", recentTeleportPos.posZ);

                data.setTag("TeleportPos", dat);
            }

            CompressedStreamTools.writeCompressed(data, output);
        } catch (Exception e) {
            CaveLog.log(Level.ERROR, e, "An error occurred trying to writing Caveworld dimension data");
        }
    }

    public static void loadDimData(NBTTagCompound data) {
        if (!data.hasKey("Seed")) {
            data.setLong("Seed", new SecureRandom().nextLong());
        }

        if (!data.hasKey("SubsurfaceHeight")) {
            data.setInteger("SubsurfaceHeight", Config.subsurfaceHeight);
        }

        dimensionSeed = data.getLong("Seed");
        subsurfaceHeight = data.getInteger("SubsurfaceHeight");

        NBTTagCompound dat = data.getCompoundTag("TeleportPos");

        if (dat != null) {
            int posX = dat.getInteger("PosX");
            int posY = dat.getInteger("PosY");
            int posZ = dat.getInteger("PosZ");

            recentTeleportPos = new ChunkCoordinates(posX, posY, posZ);
        }
    }

    public static void saveDimData() {
        if (dimData != null) {
            writeDimData();

            dimData = null;
        }
    }

    public static void regenerate(final boolean backup) {
        final File dir = getDimDir();
        final String name = dir.getName().substring(4);
        final MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance();
        Set<EntityPlayerMP> target = Sets.newHashSet();

        for (Object obj : server.getConfigurationManager().playerEntityList.toArray()) {
            if (obj != null && ((EntityPlayerMP) obj).dimension == CaveworldAPI.getDimension()) {
                target.add(CaveUtils.respawnPlayer((EntityPlayerMP) obj, 0));
            }
        }

        boolean result = new ForkJoinPool().invoke(new RecursiveTask<Boolean>() {
            @Override
            protected Boolean compute() {
                IChatComponent component;

                try {
                    component = new ChatComponentText(
                            StatCollector.translateToLocalFormatted("caveworld.regenerate.regenerating", name));
                    component.getChatStyle().setColor(EnumChatFormatting.GRAY).setItalic(true);
                    server.getConfigurationManager().sendChatMsg(component);

                    if (server.isSinglePlayer()) {
                        Caveworld.network.sendToAll(new RegenerateMessage(backup));
                    }

                    Caveworld.network.sendToAll(new RegenerateMessage.ProgressNotify(0));

                    CaveBlocks.caveworld_portal.portalDisabled = true;

                    int dim = CaveworldAPI.getDimension();
                    WorldServer world = DimensionManager.getWorld(dim);

                    if (world != null) {
                        world.saveAllChunks(true, null);
                        world.flush();

                        MinecraftForge.EVENT_BUS.post(new WorldEvent.Unload(world));

                        DimensionManager.setWorld(dim, null);
                    }

                    if (dir != null) {
                        if (backup) {
                            File parent = dir.getParentFile();
                            final Pattern pattern = Pattern.compile("^" + dir.getName() + "_bak-..*\\.zip$");
                            File[] files = parent.listFiles(new FilenameFilter() {
                                @Override
                                public boolean accept(File dir, String name) {
                                    return pattern.matcher(name).matches();
                                }
                            });

                            if (files != null && files.length >= 5) {
                                Arrays.sort(files, new Comparator<File>() {
                                    @Override
                                    public int compare(File o1, File o2) {
                                        int i = CaveUtils.compareWithNull(o1, o2);

                                        if (i == 0 && o1 != null && o2 != null) {
                                            try {
                                                i = Files.getLastModifiedTime(o1.toPath())
                                                        .compareTo(Files.getLastModifiedTime(o2.toPath()));
                                            } catch (IOException e) {
                                            }
                                        }

                                        return i;
                                    }
                                });

                                FileUtils.forceDelete(files[0]);
                            }

                            Calendar calendar = Calendar.getInstance();
                            String year = Integer.toString(calendar.get(Calendar.YEAR));
                            String month = String.format("%02d", calendar.get(Calendar.MONTH) + 1);
                            String day = String.format("%02d", calendar.get(Calendar.DATE));
                            String hour = String.format("%02d", calendar.get(Calendar.HOUR_OF_DAY));
                            String minute = String.format("%02d", calendar.get(Calendar.MINUTE));
                            String second = String.format("%02d", calendar.get(Calendar.SECOND));
                            File bak = new File(parent,
                                    dir.getName() + "_bak-" + Joiner.on("").join(year, month, day) + "-"
                                            + Joiner.on("").join(hour, minute, second) + ".zip");

                            if (bak.exists()) {
                                FileUtils.deleteQuietly(bak);
                            }

                            component = new ChatComponentText(StatCollector
                                    .translateToLocalFormatted("caveworld.regenerate.backingup", name));
                            component.getChatStyle().setColor(EnumChatFormatting.GRAY).setItalic(true);
                            server.getConfigurationManager().sendChatMsg(component);

                            Caveworld.network.sendToAll(new RegenerateMessage.ProgressNotify(1));

                            if (CaveUtils.archiveDirZip(dir, bak)) {
                                ClickEvent click = new ClickEvent(ClickEvent.Action.OPEN_FILE,
                                        FilenameUtils.normalize(bak.getParentFile().getPath()));

                                component = new ChatComponentText(StatCollector
                                        .translateToLocalFormatted("caveworld.regenerate.backedup", name));
                                component.getChatStyle().setColor(EnumChatFormatting.GRAY).setItalic(true)
                                        .setChatClickEvent(click);
                                server.getConfigurationManager().sendChatMsg(component);
                            } else {
                                component = new ChatComponentText(StatCollector
                                        .translateToLocalFormatted("caveworld.regenerate.backup.failed", name));
                                component.getChatStyle().setColor(EnumChatFormatting.RED).setItalic(true);
                                server.getConfigurationManager().sendChatMsg(component);
                            }
                        }

                        FileUtils.deleteDirectory(dir);
                    }

                    if (DimensionManager.shouldLoadSpawn(dim)) {
                        DimensionManager.initDimension(dim);

                        world = DimensionManager.getWorld(dim);

                        if (world != null) {
                            world.saveAllChunks(true, null);
                            world.flush();
                        }
                    }

                    CaveBlocks.caveworld_portal.portalDisabled = false;

                    component = new ChatComponentText(
                            StatCollector.translateToLocalFormatted("caveworld.regenerate.regenerated", name));
                    component.getChatStyle().setColor(EnumChatFormatting.GRAY).setItalic(true);
                    server.getConfigurationManager().sendChatMsg(component);

                    Caveworld.network.sendToAll(new RegenerateMessage.ProgressNotify(2));

                    return true;
                } catch (Exception e) {
                    component = new ChatComponentText(
                            StatCollector.translateToLocalFormatted("caveworld.regenerate.failed", name));
                    component.getChatStyle().setColor(EnumChatFormatting.RED).setItalic(true);
                    server.getConfigurationManager().sendChatMsg(component);

                    Caveworld.network.sendToAll(new RegenerateMessage.ProgressNotify(3));

                    CaveLog.log(Level.ERROR, e, component.getUnformattedText());
                }

                return false;
            }
        });

        if (result && (Config.hardcore || Config.caveborn)) {
            for (EntityPlayerMP player : target) {
                if (!CaveworldAPI.isEntityInCaveworld(player)) {
                    CaveUtils.forceTeleport(player, CaveworldAPI.getDimension());
                }
            }
        }
    }

    private int ambientTickCountdown = 0;

    @Override
    protected void registerWorldChunkManager() {
        worldChunkMgr = new WorldChunkManagerCaveworld(worldObj);
        dimensionId = CaveworldAPI.getDimension();
        hasNoSky = true;

        try {
            registerWorldChunkManagerTFC();
        } catch (NoSuchMethodError e) {
        }

        MapGenStructureIO.registerStructure(MapGenStrongholdCaveworld.Start.class, "Caveworld.Stronghold");
        StructureStrongholdPiecesCaveworld.registerStrongholdPieces();
    }

    @Method(modid = "terrafirmacraft")
    protected void registerWorldChunkManagerTFC() {
        MinecraftForge.EVENT_BUS.register(new TFCCaveEventHooks());

        TFC_Climate.worldPair.put(worldObj, new WorldCacheManager(worldObj));
        TFC_Core.addCDM(worldObj);

        worldChunkMgr = new TFCWorldChunkManagerCaveworld(worldObj);
    }

    @Override
    public IChunkProvider createChunkGenerator() {
        return new ChunkProviderCaveworld(worldObj);
    }

    @Override
    public boolean canCoordinateBeSpawn(int x, int z) {
        return true;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public float[] calcSunriseSunsetColors(float angle, float ticks) {
        return null;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public Vec3 getFogColor(float angle, float ticks) {
        return Vec3.createVectorHelper(0.01D, 0.01D, 0.01D);
    }

    @Override
    public int getAverageGroundLevel() {
        return 10;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public boolean getWorldHasVoidParticles() {
        return terrainType != WorldType.FLAT;
    }

    @Override
    public String getDimensionName() {
        return "Caveworld";
    }

    @Override
    public String getSaveFolder() {
        if (CaveUtils.mcpc) {
            return "DIM" + CaveworldAPI.getDimension();
        }

        return "DIM-" + getDimensionName();
    }

    @Override
    public String getWelcomeMessage() {
        return "Entering the " + getDimensionName();
    }

    @Override
    public String getDepartMessage() {
        return "Leaving the " + getDimensionName();
    }

    @Override
    public double getMovementFactor() {
        return 3.0D;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public IRenderHandler getSkyRenderer() {
        return EmptyRenderer.instance;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public IRenderHandler getCloudRenderer() {
        return EmptyRenderer.instance;
    }

    @SideOnly(Side.CLIENT)
    @Override
    public IRenderHandler getWeatherRenderer() {
        return EmptyRenderer.instance;
    }

    @Override
    public boolean shouldMapSpin(String entity, double posX, double posY, double posZ) {
        return posY < 0 || posY >= getActualHeight();
    }

    @Override
    public ChunkCoordinates getSpawnPoint() {
        return recentTeleportPos == null ? new ChunkCoordinates(0, getAverageGroundLevel(), 0) : recentTeleportPos;
    }

    @Override
    public int getRespawnDimension(EntityPlayerMP player) {
        return dimensionId;
    }

    @Override
    public boolean isDaytime() {
        return worldObj.getWorldInfo().getWorldTime() < 12500;
    }

    @Override
    public void calculateInitialWeather() {
        if (!worldObj.isRemote) {
            ambientTickCountdown = worldObj.rand.nextInt(4000) + 10000;
        }
    }

    @Override
    public void updateWeather() {
        if (!worldObj.isRemote) {
            if (--ambientTickCountdown <= 0) {
                String name;

                if (worldObj.rand.nextInt(4) == 0) {
                    name = "ambient.cave";
                } else {
                    name = "ambient.unrest";
                }

                Caveworld.network.sendToDimension(new CaveSoundMessage(new ResourceLocation("caveworld", name)),
                        dimensionId);

                ambientTickCountdown = worldObj.rand.nextInt(5000) + 10000;
            }
        }
    }

    @Override
    public long getSeed() {
        if (!worldObj.isRemote && dimData == null) {
            loadDimData(getDimData());
        }

        return dimensionSeed;
    }

    @Override
    public int getActualHeight() {
        if (!worldObj.isRemote && dimData == null) {
            loadDimData(getDimData());
        }

        return subsurfaceHeight + 1;
    }

    @Override
    public double getHorizon() {
        return getActualHeight() - 1.0D;
    }

    @Override
    public boolean canDoLightning(Chunk chunk) {
        return false;
    }

    @Override
    public boolean canDoRainSnowIce(Chunk chunk) {
        return false;
    }
}