Search in sources :

Example 1 with LevelData

use of org.lanternpowered.server.world.LanternWorldPropertiesIO.LevelData in project LanternServer by LanternPowered.

the class LanternWorldManager method copyWorld.

/**
 * Creates a world copy asynchronously using the new name given and returns
 * the new world properties if the copy was possible.
 *
 * <p>If the world is already loaded then the following will occur:</p>
 *
 * <ul>
 * <li>World is saved.</li>
 * <li>World saving is disabled.</li>
 * <li>World is copied. </li>
 * <li>World saving is enabled.</li>
 * </ul>
 *
 * @param worldProperties The world properties to copy
 * @param copyName The name for copied world
 * @return An {@link Optional} containing the properties of the new world
 *         instance, if the copy was successful
 */
public CompletableFuture<Optional<WorldProperties>> copyWorld(WorldProperties worldProperties, String copyName) {
    checkNotNull(worldProperties, "worldProperties");
    checkNotNull(copyName, "copyName");
    return Functional.asyncFailableFuture(() -> {
        // Get the new dimension id
        final int dimensionId = getNextFreeDimensionId();
        // TODO: Save the world if loaded
        // TODO: Block world saving
        // Get the lookup entry
        final WorldLookupEntry entry = this.worldByProperties.get(worldProperties);
        // The folder of the new world
        final Path targetFolder = this.getWorldFolder(copyName, dimensionId);
        // The folder of the original world
        final Path folder = entry.folder;
        if (Files.exists(targetFolder) && Files.list(targetFolder).count() > 0) {
            this.logger.error("The copy world folder already exists and it isn't empty!");
            return Optional.empty();
        }
        // Save the changes once more to make sure that they will be saved
        saveWorldProperties(worldProperties);
        // Copy the world folder
        final String folderPath = folder.toFile().getAbsolutePath();
        try {
            Files.walkFileTree(folder, new SimpleFileVisitor<Path>() {

                @Override
                public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
                    final Path dstPath = targetFolder.resolve(path.toFile().getAbsolutePath().substring(folderPath.length()));
                    Files.copy(path, dstPath, StandardCopyOption.REPLACE_EXISTING);
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            this.logger.error("Failed to copy the world folder of {}: {} to {}", copyName, folder, targetFolder, e);
            return Optional.empty();
        }
        final WorldConfigResult result = this.getOrCreateWorldConfig(copyName);
        // Copy the settings
        result.config.copyFrom(entry.properties.getConfig());
        result.config.save();
        final LevelData levelData;
        final LanternWorldProperties properties;
        try {
            levelData = LanternWorldPropertiesIO.read(folder, copyName, null);
            properties = LanternWorldPropertiesIO.convert(levelData, result.config, false);
        } catch (IOException e) {
            this.logger.error("Unable to open the copied world properties of {}", copyName, e);
            return Optional.empty();
        }
        final LevelData newData = new LevelData(levelData.worldName, levelData.uniqueId, levelData.worldData, levelData.spongeWorldData, dimensionId, null);
        // Store the new world
        this.addUpdatedWorldProperties(properties, targetFolder, dimensionId);
        // Save the changes once more to make sure that they will be saved
        LanternWorldPropertiesIO.write(targetFolder, newData);
        return Optional.of(properties);
    }, this.executor);
}
Also used : Path(java.nio.file.Path) FileVisitResult(java.nio.file.FileVisitResult) IOException(java.io.IOException) LevelData(org.lanternpowered.server.world.LanternWorldPropertiesIO.LevelData) BasicFileAttributes(java.nio.file.attribute.BasicFileAttributes)

Example 2 with LevelData

use of org.lanternpowered.server.world.LanternWorldPropertiesIO.LevelData in project LanternServer by LanternPowered.

the class LanternWorldManager method saveWorldProperties.

/**
 * Persists the given {@link WorldProperties} to the world storage for it,
 * updating any modified values.
 *
 * @param worldProperties the world properties to save
 * @return true if the save was successful
 */
public boolean saveWorldProperties(WorldProperties worldProperties) {
    checkNotNull(worldProperties, "worldProperties");
    final WorldLookupEntry entry = this.worldByProperties.get(worldProperties);
    checkNotNull(entry, "entry");
    final LanternWorldProperties worldProperties0 = (LanternWorldProperties) worldProperties;
    final BitSet dimensionMap = entry.dimensionId == 0 ? (BitSet) this.dimensionMap.clone() : null;
    try {
        final LevelData levelData = LanternWorldPropertiesIO.convert(worldProperties0, entry.dimensionId, dimensionMap);
        LanternWorldPropertiesIO.write(entry.folder, levelData);
        worldProperties0.getConfig().save();
    } catch (IOException e) {
        this.logger.error("Unable to save the world properties of {}: {}", worldProperties.getWorldName(), e.getMessage(), e);
        return false;
    }
    return true;
}
Also used : BitSet(java.util.BitSet) IOException(java.io.IOException) LevelData(org.lanternpowered.server.world.LanternWorldPropertiesIO.LevelData)

Example 3 with LevelData

use of org.lanternpowered.server.world.LanternWorldPropertiesIO.LevelData in project LanternServer by LanternPowered.

the class LanternWorldManager method init.

/**
 * Initializes the root world and the dimension id map.
 */
@SuppressWarnings("SuspiciousMethodCalls")
public void init() throws IOException {
    final Path rootWorldDir = this.rootWorldDirectory.get();
    // The properties of the root world
    LanternWorldProperties rootWorldProperties = null;
    LevelData levelData;
    if (Files.exists(rootWorldDir)) {
        try {
            levelData = LanternWorldPropertiesIO.read(rootWorldDir, null, null);
            // Create a config
            try {
                final WorldConfigResult result = getOrCreateWorldConfig(levelData.worldName);
                rootWorldProperties = LanternWorldPropertiesIO.convert(levelData, result.config, result.newCreated);
                if (result.newCreated) {
                    result.config.save();
                }
            } catch (IOException e) {
                this.logger.error("Unable to read/write the root world config, please fix this issue before loading the world.", e);
                throw e;
            }
            // Already store the data
            addUpdatedWorldProperties(rootWorldProperties, this.rootWorldDirectory.get(), 0);
        } catch (FileNotFoundException e) {
        // We can ignore this exception, because this means
        // that we have to generate the world
        } catch (IOException e) {
            this.logger.error("Unable to load root world, please fix this issue before starting the server.", e);
            throw e;
        }
    }
    // Always use a new dimension map, we will scan for the worlds
    // through folders and the dimension ids will be generated or
    // refreshed if needed
    this.dimensionMap = new BitSet();
    LanternWorldProperties rootWorldProperties0 = rootWorldProperties;
    // Generate the root (default) world if missing
    if (rootWorldProperties0 == null) {
        final String name = "Overworld";
        rootWorldProperties0 = createWorld(WorldArchetype.builder().from(WorldArchetypes.OVERWORLD).generator(GeneratorTypes.OVERWORLD).build(name, name), "", 0);
    }
    // Get all the dimensions (worlds) that should be loaded
    final List<WorldLookupEntry> loadQueue = new ArrayList<>(1);
    // Add the root dimension
    loadQueue.add(this.worldByDimensionId.get(0));
    final Map<Integer, Tuple<Path, LevelData>> idToLevelData = new HashMap<>();
    final List<Tuple<Path, LevelData>> levelDataWithoutId = new ArrayList<>();
    if (rootWorldProperties != null) {
        for (Path path : Files.list(rootWorldDir).filter(Files::isDirectory).collect(Collectors.toList())) {
            if (Files.list(path).count() == 0 || this.ignoredDirectoryNames.contains(path.getFileName().toString().toLowerCase())) {
                continue;
            }
            try {
                try {
                    levelData = LanternWorldPropertiesIO.read(path, null, null);
                } catch (FileNotFoundException e) {
                    this.logger.info("Found a invalid world directory {} inside the root world directory, the level.dat file is missing", path.getFileName().toString());
                    continue;
                }
                final Integer dimensionId;
                if (path.getFileName().toString().equalsIgnoreCase("DIM1")) {
                    dimensionId = 1;
                } else if (path.getFileName().toString().equalsIgnoreCase("DIM-1")) {
                    dimensionId = -1;
                } else if (levelData.dimensionId != null && levelData.dimensionId >= MIN_CUSTOM_DIMENSION_ID) {
                    dimensionId = levelData.dimensionId;
                } else {
                    dimensionId = null;
                }
                final Tuple<Path, LevelData> tuple = Tuple.of(path, levelData);
                if (dimensionId == null || idToLevelData.containsValue(dimensionId)) {
                    levelDataWithoutId.add(tuple);
                } else {
                    idToLevelData.put(dimensionId, tuple);
                }
            } catch (Exception e) {
                this.logger.info("Unable to load the world in the directory {}", path.getFileName().toString());
            }
        }
    }
    // Generate a dimension id for all the worlds that need it
    for (Tuple<Path, LevelData> tuple : levelDataWithoutId) {
        idToLevelData.put(getNextFreeDimensionId(), tuple);
    }
    levelDataWithoutId.clear();
    // Load the world properties and config files for all the worlds
    for (Map.Entry<Integer, Tuple<Path, LevelData>> entry : idToLevelData.entrySet()) {
        levelData = entry.getValue().getSecond();
        final LanternWorldProperties worldProperties;
        try {
            final WorldConfigResult result = getOrCreateWorldConfig(levelData.worldName);
            worldProperties = LanternWorldPropertiesIO.convert(levelData, result.config, result.newCreated);
            if (result.newCreated) {
                result.config.save();
            }
        } catch (IOException e) {
            this.logger.error("Unable to read/write the world config, please fix this issue before loading the world.", e);
            throw e;
        }
        // Store the world properties
        final WorldLookupEntry lookupEntry = addWorldProperties(worldProperties, entry.getValue().getFirst(), entry.getKey());
        // Check if it should be loaded on startup
        if (worldProperties.loadOnStartup()) {
            loadQueue.add(lookupEntry);
        }
    }
    if (!this.worldByDimensionId.containsKey(-1)) {
        final String name = "Nether";
        if (createWorld(WorldArchetype.builder().from(WorldArchetypes.THE_NETHER).generator(GeneratorTypes.NETHER).build(name, name), "DIM-1", -1).loadOnStartup()) {
            loadQueue.add(this.worldByDimensionId.get(-1));
        }
    }
    // The end
    if (!this.worldByDimensionId.containsKey(1)) {
        final String name = "TheEnd";
        if (createWorld(WorldArchetype.builder().from(WorldArchetypes.THE_END).generator(GeneratorTypes.THE_END).build(name, name), "DIM1", 1).loadOnStartup()) {
            loadQueue.add(this.worldByDimensionId.get(1));
        }
    }
    // The root world must be enabled
    rootWorldProperties0.setEnabled(true);
    // Load all the worlds
    loadQueue.forEach(this::loadWorld);
}
Also used : Path(java.nio.file.Path) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) FileNotFoundException(java.io.FileNotFoundException) BitSet(java.util.BitSet) ArrayList(java.util.ArrayList) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) RejectedExecutionException(java.util.concurrent.RejectedExecutionException) IOException(java.io.IOException) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) LevelData(org.lanternpowered.server.world.LanternWorldPropertiesIO.LevelData) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) Tuple(org.spongepowered.api.util.Tuple)

Aggregations

IOException (java.io.IOException)3 LevelData (org.lanternpowered.server.world.LanternWorldPropertiesIO.LevelData)3 Path (java.nio.file.Path)2 BitSet (java.util.BitSet)2 FileNotFoundException (java.io.FileNotFoundException)1 FileVisitResult (java.nio.file.FileVisitResult)1 BasicFileAttributes (java.nio.file.attribute.BasicFileAttributes)1 ArrayList (java.util.ArrayList)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 RejectedExecutionException (java.util.concurrent.RejectedExecutionException)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 Tuple (org.spongepowered.api.util.Tuple)1