/* * This file is part of Libelula Minecraft Edition Project. * * Libelula Minecraft Edition is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Libelula Minecraft Edition is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Libelula Minecraft Edition. * If not, see <http://www.gnu.org/licenses/>. * */ package me.libelula.capturethewool; import com.sk89q.worldedit.bukkit.selections.CuboidSelection; import com.sk89q.worldedit.bukkit.selections.Selection; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.TreeMap; import java.util.concurrent.locks.ReentrantLock; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Difficulty; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.WorldCreator; import org.bukkit.block.Block; import org.bukkit.block.Chest; import org.bukkit.block.Sign; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.generator.BlockPopulator; import org.bukkit.generator.ChunkGenerator; import org.bukkit.util.FileUtil; /** * * @author Diego D'Onofrio <ddonofrio@member.fsf.org> * @version 1.0 * */ public final class WorldManager { private final Main plugin; private final EmptyGenerator eg; private final YamlConfiguration worlds; private final File worldsConfigFile; private final List<Location> lobbySpawnLocations; private int currentLobbySpawnPoint; private final TreeMap<String, CuboidSelection> restoreAreas; private final ReentrantLock _restoreAreas_mutex; public class EmptyGenerator extends ChunkGenerator { private final ArrayList<BlockPopulator> populator; private final byte[][] blocks; public EmptyGenerator() { super(); populator = new ArrayList<>(); blocks = new byte[256 / 16][]; } @Override public List<BlockPopulator> getDefaultPopulators(World world) { return populator; } @Override public boolean canSpawn(World world, int x, int z) { return true; } @Override public byte[][] generateBlockSections(World world, Random random, int x, int z, BiomeGrid biomes) { return blocks; } } public WorldManager(Main plugin) { this.plugin = plugin; eg = new EmptyGenerator(); worlds = new YamlConfiguration(); worldsConfigFile = new File(plugin.getDataFolder(), "worlds.yml"); lobbySpawnLocations = new ArrayList<>(); load(); currentLobbySpawnPoint = 0; _restoreAreas_mutex = new ReentrantLock(true); restoreAreas = new TreeMap<>(); } public void load() { if (worldsConfigFile.exists()) { try { worlds.load(worldsConfigFile); } catch (IOException | InvalidConfigurationException ex) { plugin.getLogger().severe(ex.toString()); } } lobbySpawnLocations.clear(); processLobbySpawnList(); } public void persist() { try { worlds.save(worldsConfigFile); } catch (IOException ex) { plugin.getLogger().severe(ex.toString()); } } public EmptyGenerator getEmptyWorldGenerator() { return eg; } private void setDefaults(World world) { world.setAmbientSpawnLimit(0); world.setAnimalSpawnLimit(0); world.setAutoSave(true); world.setDifficulty(Difficulty.EASY); world.setGameRuleValue("doMobSpawning", "false"); world.setMonsterSpawnLimit(0); world.setPVP(true); world.setWaterAnimalSpawnLimit(0); world.setWeatherDuration(Integer.MAX_VALUE); } public World loadWorld(String worldName) { World world = plugin.getServer().getWorld(worldName); if (world == null) { File worldDir = new File(worldName); if (worldDir.exists() && worldDir.isDirectory()) { WorldCreator creator = WorldCreator.name(worldName).seed(0). environment(World.Environment.NORMAL); creator.generator(getEmptyWorldGenerator()); world = Bukkit.createWorld(creator); } } if (world != null) { setDefaults(world); } return world; } private World createWorld(String worldName) { World world = loadWorld(worldName); if (world == null) { Random r = new Random(); long seed = (long) (r.nextDouble() * Long.MAX_VALUE); World.Environment e = World.Environment.NORMAL; WorldCreator creator = WorldCreator.name(worldName).seed(seed).environment(e); creator.generator(getEmptyWorldGenerator()); world = Bukkit.createWorld(creator); setDefaults(world); } return world; } public World createEmptyWorld(String worldName) { World world = createWorld(worldName); world.getBlockAt(0, 61, 0).setType(Material.GLASS); world.setSpawnLocation(0, 63, 0); return world; } public void clearEntities(World world) { for (Entity entity : world.getEntities()) { if (entity.getType() != EntityType.ITEM_FRAME && entity.getType() != EntityType.PLAYER) { entity.remove(); } } } public boolean unloadWorld(final World world) { for (Player player : world.getPlayers()) { player.teleport(getNextLobbySpawn()); } for (Player player : world.getPlayers()) { player.kickPlayer(""); } clearEntities(world); world.setKeepSpawnInMemory(false); for (Chunk chunk : world.getLoadedChunks()) { world.unloadChunk(chunk); } boolean ret = Bukkit.unloadWorld(world, false); return ret; } /** * * @param world the world to be copied. * @param newWorld the new world name * @return true if done, false on failure. */ public World cloneWorld(World world, String newWorld) { return cloneWorld(world, newWorld, true); } public World cloneWorld(World world, String newWorld, boolean load) { File newWorldDir = new File(newWorld); if (newWorldDir.exists()) { return null; } try { copyFolder(world.getWorldFolder(), newWorldDir); } catch (IOException ex) { plugin.getLogger().severe(ex.toString()); return null; } File uidFile = new File(newWorld, "uid.dat"); uidFile.delete(); World ret; if (load) { ret = loadWorld(newWorld); } else { ret = null; } return ret; } public boolean cloneRegions(World origin, String destination) { File regionDir = new File(destination, "region"); if (!regionDir.exists()) { return false; } try { delete(regionDir); } catch (IOException ex) { plugin.getLogger().severe(ex.toString()); return false; } try { copyFolder(new File(origin.getWorldFolder(), "region"), regionDir); } catch (IOException ex) { plugin.getLogger().severe(ex.toString()); return false; } return true; } public boolean eraseWorld(String worldName) { return eraseWorld(worldName, true); } public boolean eraseWorld(String worldName, boolean test) { if (test) { World world = plugin.getServer().getWorld(worldName); if (world != null) { unloadWorld(world); } } File worldDir = new File(worldName); if (worldDir.exists() && worldDir.isDirectory()) { try { delete(worldDir); return true; } catch (IOException ex) { plugin.getLogger().severe(ex.toString()); } } return false; } private void delete(File f) throws IOException { if (f.isDirectory()) { for (File c : f.listFiles()) { delete(c); } } f.delete(); } private static void copyFolder(File src, File dest) throws IOException { if (src.isDirectory()) { if (!dest.exists()) { dest.mkdir(); } String files[] = src.list(); for (String file : files) { File srcFile = new File(src, file); File destFile = new File(dest, file); copyFolder(srcFile, destFile); } } else { if (!FileUtil.copy(src, dest)) { System.out.println("Error copying: " + src.getAbsolutePath() + " to " + dest.getAbsolutePath()); } } } public World getLobbyWorld() { if (lobbySpawnLocations.isEmpty()) { return null; } return lobbySpawnLocations.get(0).getWorld(); } public void addSpawnLocation(Location spawnPoint) { String key = spawnPoint.getBlockX() + "x" + spawnPoint.getBlockY() + "y" + spawnPoint.getBlockZ() + "z"; worlds.set("lobby.spawnpoints." + key + ".x", spawnPoint.getX()); worlds.set("lobby.spawnpoints." + key + ".y", spawnPoint.getY()); worlds.set("lobby.spawnpoints." + key + ".z", spawnPoint.getZ()); worlds.set("lobby.spawnpoints." + key + ".pitch", spawnPoint.getPitch()); worlds.set("lobby.spawnpoints." + key + ".yaw", spawnPoint.getYaw()); for (int n = 0; n < lobbySpawnLocations.size(); n++) { Location loc = lobbySpawnLocations.get(n); if (loc.getBlockX() == spawnPoint.getBlockX() && loc.getBlockY() == spawnPoint.getBlockY() && loc.getBlockZ() == spawnPoint.getBlockZ()) { lobbySpawnLocations.remove(n); break; } } lobbySpawnLocations.add(spawnPoint); worlds.set("lobby.world", spawnPoint.getWorld().getName()); } private void processLobbySpawnList() { String worldName = worlds.getString("lobby.world"); if (worldName == null) { return; } World lobbyWorld = loadWorld(worldName); if (lobbyWorld == null) { return; } double x; double y; double z; double pitch; double yaw; for (String spawnPoint : worlds.getConfigurationSection("lobby.spawnpoints").getKeys(false)) { x = worlds.getDouble("lobby.spawnpoints." + spawnPoint + ".x"); y = worlds.getDouble("lobby.spawnpoints." + spawnPoint + ".y"); z = worlds.getDouble("lobby.spawnpoints." + spawnPoint + ".z"); pitch = worlds.getDouble("lobby.spawnpoints." + spawnPoint + ".pitch"); yaw = worlds.getDouble("lobby.spawnpoints." + spawnPoint + ".yaw"); lobbySpawnLocations.add(new Location(lobbyWorld, x, y, z, (float) yaw, (float) pitch)); } } public List<Location> getLobbySpawnLocations() { return lobbySpawnLocations; } public void clearLobbyInformation() { lobbySpawnLocations.clear(); } public Location getNextLobbySpawn() { Location ret; if (currentLobbySpawnPoint >= lobbySpawnLocations.size()) { currentLobbySpawnPoint = 0; } ret = lobbySpawnLocations.get(currentLobbySpawnPoint); currentLobbySpawnPoint++; return ret; } public boolean isOnLobby(Player player) { return getLobbyWorld().getName().equals(player.getWorld().getName()); } public void addModificationPoint(Location loc) { CuboidSelection cs = restoreAreas.get(loc.getWorld().getName()); if (cs == null) { cs = new CuboidSelection(loc.getWorld(), loc, loc); } else { Location min = cs.getMinimumPoint(); Location max = cs.getMaximumPoint(); if (min.getBlockX() > loc.getBlockX()) { min.setX(loc.getBlockX()); } if (min.getBlockY() > loc.getBlockY()) { min.setX(loc.getBlockY()); } if (min.getBlockZ() > loc.getBlockZ()) { min.setX(loc.getBlockZ()); } if (max.getBlockX() < loc.getBlockX()) { max.setX(loc.getBlockX()); } if (max.getBlockY() < loc.getBlockY()) { max.setX(loc.getBlockY()); } if (max.getBlockZ() < loc.getBlockZ()) { max.setX(loc.getBlockZ()); } cs = new CuboidSelection(loc.getWorld(), min, max); } _restoreAreas_mutex.lock(); try { restoreAreas.put(loc.getWorld().getName(), cs); } finally { _restoreAreas_mutex.unlock(); } } public void restoreMap(final MapManager.MapData map, final World roomMap) { Location min = map.restaurationArea.getMinimumPoint(); Location max = map.restaurationArea.getMaximumPoint(); int count = 1; final World source = map.world; if (source == null) { return; } for (int X = min.getBlockX(); X <= max.getBlockX(); X++) { Location areaMin = new Location(source, X, min.getBlockY(), min.getBlockZ()); Location areaMax = new Location(source, X, max.getBlockY(), max.getBlockZ()); final Selection sel = new CuboidSelection(source, areaMin, areaMax); Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { @Override public void run() { cloneRegion(plugin, source, roomMap, sel); } }, count); count = count + 2; } Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { @Override public void run() { plugin.rm.removeWools(map.world.getName(), roomMap); } }, count); } private static void cloneRegion(final Main plugin, World source, World destination, Selection area) { Location min = area.getMinimumPoint(); Location max = area.getMaximumPoint(); for (int X = min.getBlockX(); X <= max.getBlockX(); X++) { for (int Y = min.getBlockY(); Y <= max.getBlockY(); Y++) { for (int Z = min.getBlockZ(); Z <= max.getBlockZ(); Z++) { final Block src = source.getBlockAt(X, Y, Z); final Block dst = destination.getBlockAt(X, Y, Z); dst.setTypeIdAndData(src.getTypeId(), src.getData(), false); if (src.getType() == Material.SIGN_POST || src.getType() == Material.WALL_SIGN) { final Sign s = (Sign) src.getState(); final Sign d = (Sign) dst.getState(); Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { @Override public void run() { d.setLine(0, s.getLine(0)); d.setLine(1, s.getLine(1)); d.setLine(2, s.getLine(2)); d.setLine(3, s.getLine(3)); d.update(); } }, 1); } else if (src.getType() == Material.CHEST || src.getType() == Material.TRAPPED_CHEST) { Bukkit.getScheduler().runTaskLater(plugin, new Runnable() { @Override public void run() { final Chest s = (Chest) src.getState(); final Chest d = (Chest) dst.getState(); try { d.getInventory().setContents(s.getInventory().getContents()); } catch (IllegalArgumentException ex) { // Do nothing. } } }, 1); } } } } plugin.wm.clearEntities(destination); } }