ProjectAres/PGM/src/main/java/tc/oc/pgm/terrain/WorldManagerImpl.java

139 lines
4.5 KiB
Java

package tc.oc.pgm.terrain;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
import javax.inject.Inject;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.WorldCreator;
import tc.oc.commons.core.FileUtils;
import tc.oc.pgm.map.MapInfo;
import tc.oc.pgm.module.ModuleLoadException;
import static com.google.common.base.Preconditions.checkState;
/**
* Provides handy methods to load, save, and archive match worlds.
*/
public class WorldManagerImpl implements WorldManager {
private final Server server;
private final MapInfo mapInfo;
private final TerrainOptions terrainOptions;
private final Set<WorldConfigurator> worldConfigurators;
@Inject private WorldManagerImpl(Server server, MapInfo mapInfo, TerrainOptions terrainOptions, Set<WorldConfigurator> worldConfigurators) {
this.server = server;
this.mapInfo = mapInfo;
this.terrainOptions = terrainOptions;
this.worldConfigurators = worldConfigurators;
}
private File worldFolder(String worldName) {
return new File(server.getWorldContainer(), worldName);
}
private void destroy(String worldName) throws IOException {
final File folder = worldFolder(worldName);
if(folder.exists()) {
FileUtils.delete(folder);
}
}
private void copyDirs(File source, File dest, String... names) throws IOException {
for(String name : names) {
final File dir = new File(source, name);
if(dir.isDirectory()) {
FileUtils.copy(dir, new File(dest, name));
}
}
}
private void copy(File source, String worldName) throws IOException {
final File folder = worldFolder(worldName);
// only copy level.dat, region/, and data/
if(!folder.mkdir()) {
throw new IOException("Failed to create temporary world folder " + folder);
}
FileUtils.copy(new File(source, "level.dat"), new File(folder, "level.dat"));
copyDirs(source, folder, "region", "data", "structures");
}
private void importDestructive(File source, String worldName) throws IOException {
destroy(worldName);
copy(source, worldName);
}
private WorldCreator worldCreator(String worldName) {
final WorldCreator creator = server.detectWorld(worldName);
return creator != null ? creator : new WorldCreator(worldName);
}
@Override
public World createWorld(String worldName) throws ModuleLoadException, IOException {
if(server.getWorlds().isEmpty()) {
throw new IllegalStateException("Can't create a world because there is no default world to derive it from");
}
try {
importDestructive(terrainOptions.worldFolder().toFile(), worldName);
} catch(FileNotFoundException e) {
// If files are missing, just inform the mapmaker.
// Other IOExceptions are considered internal errors.
throw new ModuleLoadException(e.getMessage()); // Don't set the cause, it's redundant
}
final WorldCreator creator = worldCreator(worldName);
worldConfigurators.forEach(wc -> wc.configureWorld(creator));
final World world = server.createWorld(creator);
if(world == null) {
throw new IllegalStateException("Failed to create world (Server.createWorld returned null)");
}
world.setAutoSave(false);
world.setKeepSpawnInMemory(false);
world.setDifficulty(Optional.ofNullable(mapInfo.difficulty)
.orElseGet(() -> server.getWorlds().get(0).getDifficulty()));
return world;
}
@Override
public void unloadWorld(World world) {
this.server.unloadWorld(world, true);
}
@Override
public void destroyWorld(String worldName, @Nullable File archive) {
File folder = worldFolder(worldName);
if(!folder.exists()) return;
if(archive != null) {
cleanWorldDirectory(folder);
checkState(folder.renameTo(archive));
} else {
FileUtils.delete(folder);
}
}
/**
* Cleans the world directory of generated files. Currently it deletes:
* - session.lock
* - uid.dat
*
* @param dir File pointing to the world directory.
*/
private void cleanWorldDirectory(File dir) {
new File(dir, "session.lock").delete();
new File(dir, "uid.dat").delete();
}
}