From 54e1612f519a52b3b4a27f2e39862b491d5abc4d Mon Sep 17 00:00:00 2001 From: Ashcon Partovi Date: Sat, 28 Apr 2018 17:14:31 -0700 Subject: [PATCH] Parse rotations from YML files --- .../oc/pgm/rotation/FileRotationProvider.java | 72 +++++-------------- .../rotation/FileRotationProviderFactory.java | 68 ++++++++++++------ .../oc/pgm/rotation/RotationProviderInfo.java | 3 +- 3 files changed, 66 insertions(+), 77 deletions(-) diff --git a/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProvider.java b/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProvider.java index 87cb27b..c1f85e7 100644 --- a/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProvider.java +++ b/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProvider.java @@ -3,6 +3,8 @@ package tc.oc.pgm.rotation; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.concurrent.ExecutorService; @@ -12,11 +14,12 @@ import java.util.logging.Level; import java.util.logging.Logger; import javax.annotation.Nonnull; -import com.google.common.base.Charsets; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import java.time.Instant; +import com.google.common.util.concurrent.Futures; +import org.bukkit.configuration.file.YamlConfiguration; import tc.oc.api.docs.virtual.ServerDoc; import tc.oc.commons.core.logging.ClassLogger; import tc.oc.commons.core.util.Joiners; @@ -25,35 +28,26 @@ import tc.oc.pgm.map.MapLibrary; import tc.oc.pgm.map.PGMMap; public class FileRotationProvider extends AbstractRotationProvider { - public static final String FILE_NEXTID_SUFFIX = ".next"; - public static final int DEFAULT_NEXTID = 0; - private final Logger logger; private final Logger mapLogger; private final MapLibrary mapLibrary; private final String name; private final Path rotationFile; - private final Path dataPath; private final Optional rotationApi; + private final boolean shuffle; - public FileRotationProvider(MapLibrary mapLibrary, String name, Path rotationFile, Path dataPath, Optional rotationApi) { + public FileRotationProvider(MapLibrary mapLibrary, String name, Path rotationFile, Optional rotationApi, boolean shuffle) { Preconditions.checkNotNull(mapLibrary, "map manager"); Preconditions.checkNotNull(rotationFile, "rotation path"); - Preconditions.checkNotNull(dataPath, "data path"); Preconditions.checkArgument(Files.isRegularFile(rotationFile), "rotation path must be a file"); - Preconditions.checkArgument(Files.isDirectory(dataPath), "data path must be a directory"); this.logger = ClassLogger.get(PGM.get().getLogger(), getClass()); this.mapLogger = PGM.get().getRootMapLogger(); this.mapLibrary = mapLibrary; this.name = name; this.rotationFile = rotationFile; - this.dataPath = dataPath; this.rotationApi = rotationApi; - } - - Path nextIdFile() { - return dataPath.resolve(name + FILE_NEXTID_SUFFIX); + this.shuffle = shuffle; } @Override @@ -69,7 +63,7 @@ public class FileRotationProvider extends AbstractRotationProvider { private RotationState loadRotationFromDisk() throws IOException { List maps = this.parseRotationNames(); - int nextId = this.parseNextId(maps); + int nextId = this.fetchNextId(maps); if(maps.isEmpty()) { throw new IOException(String.format("Rotation '%s' was empty!", name)); @@ -84,36 +78,17 @@ public class FileRotationProvider extends AbstractRotationProvider { return new RotationState(maps, nextId); } - private int parseNextId(List maps) { - List lines; - try { - lines = Files.readAllLines(nextIdFile(), Charsets.UTF_8); - } catch (IOException e) { - return rotationApi.map(rot -> maps.indexOf(mapLibrary.getMapByNameOrId(rot.next_map_id()).get())) - .flatMap(index -> Optional.ofNullable(index >= 0 ? index : null)) - .orElseGet(() -> { - this.logger.warning("Failed to read next id from " + nextIdFile().toString()); - return DEFAULT_NEXTID; - }); - } - - for(String line : lines) { - try { - return Integer.parseInt(line); - } catch (NumberFormatException e) { - continue; - } - } - - this.logger.warning("Failed to parse next id from " + nextIdFile().toString()); - return DEFAULT_NEXTID; + // TODO: Provide an alternative implementation for no API + private int fetchNextId(List maps) { + return rotationApi.map(rot -> maps.indexOf(mapLibrary.getMapByNameOrId(rot.next_map_id()).get())) + .flatMap(index -> Optional.ofNullable(index >= 0 ? index : null)) + .orElse(0); } private List parseRotationNames() throws IOException { - List lines = Files.readAllLines(rotationFile, Charsets.UTF_8); - - ImmutableList.Builder maps = ImmutableList.builder(); - for(String line : lines) { + YamlConfiguration yaml = YamlConfiguration.loadConfiguration(rotationFile.toFile()); + List maps = new ArrayList<>(); + for(String line : yaml.getStringList("maps")) { line = line.trim(); if(line.isEmpty()) { continue; @@ -126,23 +101,14 @@ public class FileRotationProvider extends AbstractRotationProvider { mapLogger.severe("Unknown map '" + line + "' when parsing " + rotationFile.toString()); } } - - return maps.build(); + if(shuffle) Collections.shuffle(maps); + return ImmutableList.copyOf(maps); } @Override public Future saveRotation(@Nonnull final String name, @Nonnull final RotationState rotation) { this.setRotation(name, rotation); - return getExecutorService().submit(() -> saveRotationToDisk(name, rotation)); - } - - private void saveRotationToDisk(@Nonnull String name, @Nonnull RotationState rotation) { - List nextIdSerialized = ImmutableList.of(Integer.toString(rotation.getNextId())); - try { - Files.write(nextIdFile(), nextIdSerialized, Charsets.UTF_8); - } catch (IOException e) { - this.logger.log(Level.SEVERE, "Failed to save next id for rotation: " + name, e); - } + return Futures.immediateFuture(null); } private static @Nonnull ExecutorService getExecutorService() { diff --git a/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProviderFactory.java b/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProviderFactory.java index 5f27a9e..2e39f1c 100644 --- a/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProviderFactory.java +++ b/PGM/src/main/java/tc/oc/pgm/rotation/FileRotationProviderFactory.java @@ -1,5 +1,7 @@ package tc.oc.pgm.rotation; +import java.io.File; +import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -11,6 +13,8 @@ import javax.inject.Inject; import org.bukkit.configuration.Configuration; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; +import org.yaml.snakeyaml.Yaml; import tc.oc.api.docs.virtual.ServerDoc; import tc.oc.api.minecraft.MinecraftService; import tc.oc.pgm.map.MapLibrary; @@ -24,32 +28,52 @@ public class FileRotationProviderFactory { } public Set parse(MapLibrary mapLibrary, Path dataPath, Configuration config) { - ConfigurationSection base = config.getConfigurationSection("rotation.providers.file"); + ConfigurationSection base = config.getConfigurationSection("rotation.providers"); if(base == null) return Collections.emptySet(); - Set providers = new HashSet<>(); - for(String name : base.getKeys(false)) { - ConfigurationSection provider = base.getConfigurationSection(name); - - Path rotationFile = Paths.get(provider.getString("path")); - if(!rotationFile.isAbsolute()) rotationFile = dataPath.resolve(rotationFile); - - int priority = provider.getInt("priority", 0); - int count = provider.getInt("count", 0); - Optional next = minecraftService.getLocalServer() - .rotations() - .stream() - .filter(rot -> rot.name().equals(name) && mapLibrary.getMapByNameOrId(rot.next_map_id()).isPresent()) - .findFirst(); - - if(Files.isRegularFile(rotationFile)) { - providers.add(new RotationProviderInfo(new FileRotationProvider(mapLibrary, name, rotationFile, dataPath, next), name, priority, count)); - } else if(minecraftService.getLocalServer().startup_visibility() == ServerDoc.Visibility.PUBLIC) { - // This is not a perfect way to decide whether or not to throw an error, but it's the best we can do right now - mapLibrary.getLogger().severe("Missing rotation file: " + rotationFile); + for(String pathString : base.getStringList("files")) { + Path path = Paths.get(pathString); + if(!path.isAbsolute()) path = dataPath.resolve(path); + File file = path.toFile(); + if(file.isDirectory()) { + try { + Files.walk(path) + .filter(Files::isRegularFile) + .filter(this::isYaml) + .map(Path::toFile) + .forEach(f -> providers.add(parse(mapLibrary, f, YamlConfiguration.loadConfiguration(f)))); + } catch(IOException e) { + e.printStackTrace(); + } + } else if(file.isFile()) { + providers.add(parse(mapLibrary, file, YamlConfiguration.loadConfiguration(file))); } } - return providers; } + + public RotationProviderInfo parse(MapLibrary mapLibrary, File file, YamlConfiguration yaml) { + String name = yaml.getString("name", "default"); + int priority = yaml.getInt("priority", 0); + int count = yaml.getInt("count", 0); + boolean shuffle = yaml.getBoolean("shuffle", false); + Optional next = minecraftService.getLocalServer() + .rotations() + .stream() + .filter(rot -> rot.name().equals(name) && mapLibrary.getMapByNameOrId(rot.next_map_id()).isPresent()) + .findFirst(); + return new RotationProviderInfo( + new FileRotationProvider(mapLibrary, name, Paths.get(file.getAbsolutePath()), next, shuffle), + name, priority, count + ); + } + + private boolean isYaml(Path path) { + try { + new YamlConfiguration().load(path.toFile()); + return true; + } catch(Exception e) { + return false; + } + } } diff --git a/PGM/src/main/java/tc/oc/pgm/rotation/RotationProviderInfo.java b/PGM/src/main/java/tc/oc/pgm/rotation/RotationProviderInfo.java index c9333f2..146a40f 100644 --- a/PGM/src/main/java/tc/oc/pgm/rotation/RotationProviderInfo.java +++ b/PGM/src/main/java/tc/oc/pgm/rotation/RotationProviderInfo.java @@ -5,8 +5,7 @@ import javax.annotation.Nonnull; import com.google.common.base.Preconditions; public class RotationProviderInfo implements Comparable { - public final @Nonnull - RotationProvider provider; + public final @Nonnull RotationProvider provider; public final int priority; public final int count; public final @Nonnull String name;