Parse rotations from YML files

This commit is contained in:
Ashcon Partovi 2018-04-28 17:14:31 -07:00 committed by GitHub
parent 1c6c6f1c6f
commit 54e1612f51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 66 additions and 77 deletions

View File

@ -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<ServerDoc.Rotation> rotationApi;
private final boolean shuffle;
public FileRotationProvider(MapLibrary mapLibrary, String name, Path rotationFile, Path dataPath, Optional<ServerDoc.Rotation> rotationApi) {
public FileRotationProvider(MapLibrary mapLibrary, String name, Path rotationFile, Optional<ServerDoc.Rotation> 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<PGMMap> 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<PGMMap> maps) {
List<String> 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<PGMMap> 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<PGMMap> parseRotationNames() throws IOException {
List<String> lines = Files.readAllLines(rotationFile, Charsets.UTF_8);
ImmutableList.Builder<PGMMap> maps = ImmutableList.builder();
for(String line : lines) {
YamlConfiguration yaml = YamlConfiguration.loadConfiguration(rotationFile.toFile());
List<PGMMap> 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<String> 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() {

View File

@ -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<RotationProviderInfo> 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<RotationProviderInfo> 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<ServerDoc.Rotation> 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<ServerDoc.Rotation> 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;
}
}
}

View File

@ -5,8 +5,7 @@ import javax.annotation.Nonnull;
import com.google.common.base.Preconditions;
public class RotationProviderInfo implements Comparable<RotationProviderInfo> {
public final @Nonnull
RotationProvider provider;
public final @Nonnull RotationProvider provider;
public final int priority;
public final int count;
public final @Nonnull String name;