Store rotation state in the database

This commit is contained in:
Electroid 2017-07-28 02:45:13 -07:00
parent 55aacbddb1
commit 0caea52598
7 changed files with 73 additions and 18 deletions

View File

@ -106,7 +106,7 @@ public interface ServerDoc {
* Startup info received from the API
*/
@Serialize
interface Configuration extends Partial {
interface Configuration extends Rotations {
String settings_profile();
Map<UUID, String> operators();
@Nullable Team team();
@ -117,7 +117,6 @@ public interface ServerDoc {
Visibility startup_visibility();
boolean whitelist_enabled();
boolean waiting_room();
@Nullable String resource_pack_url();
@Nullable String resource_pack_sha1();
boolean resource_pack_fast_update();
@ -142,6 +141,17 @@ public interface ServerDoc {
Set<String> queued_mutations();
}
@Serialize
interface Rotations extends Partial {
List<Rotation> rotations();
}
@Serialize
interface Rotation extends Document {
String name();
String next_map_id();
}
/**
* Status sent to the API from Lobby
*/

View File

@ -282,4 +282,9 @@ public class LocalServerDocument extends StartupServerDocument implements Server
public Set<String> queued_mutations() {
return mutations != null ? mutations.queued_mutations() : Collections.emptySet();
}
@Override
public List<ServerDoc.Rotation> rotations() {
return Collections.emptyList();
}
}

View File

@ -209,7 +209,13 @@ public class MapCommands {
final RotationState rotation = CommandUtils.getRotation(args.getFlag('n'), sender);
int page = args.getInteger(0, 1);
new PrettyPaginatedResult<PGMMap>(PGMTranslations.get().t("command.map.currentRotation.title", sender) + "(" + ChatColor.DARK_AQUA + PGM.getMatchManager().getRotationManager().getCurrentRotationName() + ChatColor.RESET + ")") {
String header = PGMTranslations.get().t("command.map.currentRotation.title", sender);
String name = PGM.getMatchManager().getRotationManager().getCurrentRotationName();
if(!name.equalsIgnoreCase("default")) {
header += " (" + ChatColor.DARK_AQUA + name + ChatColor.RESET + ")";
}
new PrettyPaginatedResult<PGMMap>(header) {
@Override public String format(PGMMap map, int index) {
ChatColor color = index == rotation.getNextId() ? ChatColor.DARK_AQUA : ChatColor.WHITE;
return color.toString() + (index + 1) + ". " + map.getInfo().getShortDescription(sender);

View File

@ -20,6 +20,7 @@ import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.configuration.Configuration;
import org.bukkit.event.EventBus;
import tc.oc.api.minecraft.MinecraftService;
import tc.oc.api.util.Permissions;
import tc.oc.commons.core.logging.Loggers;
import tc.oc.pgm.PGM;
@ -48,6 +49,7 @@ public class MatchManager implements MatchFinder {
private final FileRotationProviderFactory fileRotationProviderFactory;
private final EventBus eventBus;
private final MatchLoader matchLoader;
private final MinecraftService minecraftService;
private @Nullable RotationManager rotationManager;
/** Custom set next map. */
@ -64,7 +66,8 @@ public class MatchManager implements MatchFinder {
MapErrorTracker mapErrorTracker,
FileRotationProviderFactory fileRotationProviderFactory,
EventBus eventBus,
MatchLoader matchLoader) throws MapNotFoundException {
MatchLoader matchLoader,
MinecraftService minecraftService) throws MapNotFoundException {
this.pluginDataFolder = pluginDataFolder;
this.mapErrorTracker = mapErrorTracker;
@ -75,6 +78,7 @@ public class MatchManager implements MatchFinder {
this.mapLoader = mapLoader;
this.eventBus = eventBus;
this.matchLoader = matchLoader;
this.minecraftService = minecraftService;
}
@Override
@ -126,6 +130,7 @@ public class MatchManager implements MatchFinder {
if(rotationManager == null) {
rotationManager = new RotationManager(
log,
minecraftService,
config.get(),
mapLibrary.getMaps().iterator().next(),
fileRotationProviderFactory.parse(

View File

@ -16,6 +16,8 @@ import com.google.common.base.Charsets;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.time.Instant;
import tc.oc.api.docs.virtual.ServerDoc;
import tc.oc.commons.core.logging.ClassLogger;
import tc.oc.commons.core.util.Joiners;
import tc.oc.pgm.PGM;
@ -32,8 +34,9 @@ public class FileRotationProvider extends AbstractRotationProvider {
private final String name;
private final Path rotationFile;
private final Path dataPath;
private final Optional<ServerDoc.Rotation> rotationApi;
public FileRotationProvider(MapLibrary mapLibrary, String name, Path rotationFile, Path dataPath) {
public FileRotationProvider(MapLibrary mapLibrary, String name, Path rotationFile, Path dataPath, Optional<ServerDoc.Rotation> rotationApi) {
Preconditions.checkNotNull(mapLibrary, "map manager");
Preconditions.checkNotNull(rotationFile, "rotation path");
Preconditions.checkNotNull(dataPath, "data path");
@ -46,6 +49,7 @@ public class FileRotationProvider extends AbstractRotationProvider {
this.name = name;
this.rotationFile = rotationFile;
this.dataPath = dataPath;
this.rotationApi = rotationApi;
}
Path nextIdFile() {
@ -54,7 +58,7 @@ public class FileRotationProvider extends AbstractRotationProvider {
@Override
public @Nonnull Future<?> loadRotations() {
return getExecutorService().submit((Runnable) () -> {
return getExecutorService().submit(() -> {
try {
setRotation(name, loadRotationFromDisk(), Instant.now());
} catch(IOException e) {
@ -64,8 +68,8 @@ public class FileRotationProvider extends AbstractRotationProvider {
}
private RotationState loadRotationFromDisk() throws IOException {
int nextId = this.parseNextId();
List<PGMMap> maps = this.parseRotationNames();
int nextId = this.parseNextId(maps);
if(maps.isEmpty()) {
throw new IOException(String.format("Rotation '%s' was empty!", name));
@ -80,13 +84,17 @@ public class FileRotationProvider extends AbstractRotationProvider {
return new RotationState(maps, nextId);
}
private int parseNextId() {
private int parseNextId(List<PGMMap> maps) {
List<String> lines;
try {
lines = Files.readAllLines(nextIdFile(), Charsets.UTF_8);
} catch (IOException e) {
this.logger.warning("Failed to read next id from " + nextIdFile().toString());
return DEFAULT_NEXTID;
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) {
@ -125,11 +133,7 @@ public class FileRotationProvider extends AbstractRotationProvider {
@Override
public Future<?> saveRotation(@Nonnull final String name, @Nonnull final RotationState rotation) {
this.setRotation(name, rotation);
return getExecutorService().submit(new Runnable() {
@Override public void run() {
FileRotationProvider.this.saveRotationToDisk(name, rotation);
}
});
return getExecutorService().submit(() -> saveRotationToDisk(name, rotation));
}
private void saveRotationToDisk(@Nonnull String name, @Nonnull RotationState rotation) {

View File

@ -5,6 +5,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import javax.inject.Inject;
@ -35,9 +36,14 @@ public class FileRotationProviderFactory {
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), name, priority, count));
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);

View File

@ -4,6 +4,7 @@ import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
@ -13,6 +14,7 @@ import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
@ -22,6 +24,8 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import org.bukkit.configuration.Configuration;
import tc.oc.api.docs.virtual.ServerDoc;
import tc.oc.api.minecraft.MinecraftService;
import tc.oc.commons.core.logging.ClassLogger;
import tc.oc.pgm.map.PGMMap;
@ -30,13 +34,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
public class RotationManager {
private final Logger logger;
private final MinecraftService minecraftService;
private final Configuration config;
private final SortedSet<RotationProviderInfo> providers;
private String currentRotationName;
private RotationState defaultRotation;
public RotationManager(Logger logger, Configuration config, PGMMap defaultMap, Collection<RotationProviderInfo> providers) {
public RotationManager(Logger logger, MinecraftService minecraftService, Configuration config, PGMMap defaultMap, Collection<RotationProviderInfo> providers) {
this.logger = ClassLogger.get(checkNotNull(logger, "logger"), getClass());
this.minecraftService = minecraftService;
this.config = config;
this.providers = Collections.synchronizedSortedSet(Sets.newTreeSet(providers));
@ -85,6 +91,16 @@ public class RotationManager {
for(RotationProviderInfo info : this.providers) {
info.provider.saveRotation(name, rotation);
}
minecraftService.updateLocalServer((ServerDoc.Rotations) () ->
getRotations().entrySet()
.stream()
.map(entry -> new ServerDoc.Rotation() {
public String name() { return entry.getKey(); }
public String next_map_id() { return entry.getValue().getNext().getId().slug(); }
})
.sorted(Comparator.comparing(ServerDoc.Rotation::name, (r1, r2) -> r1.equals(name) ? -1 : 1))
.collect(Collectors.toList()));
}
public @Nonnull String getCurrentRotationName() {
@ -136,7 +152,10 @@ public class RotationManager {
*/
public boolean load(PGMMap defaultMap) {
this.defaultRotation = new RotationState(Collections.singletonList(defaultMap), 0);
this.currentRotationName = config.getString("rotation.default-name", "default");
List<ServerDoc.Rotation> rotations = minecraftService.getLocalServer().rotations();
this.currentRotationName = rotations.isEmpty() ? config.getString("rotation.default-name", "default") : rotations.get(0).name();
logger.info("Loading rotations from " + providers.size() +
" providers. Fallback map is '" + defaultRotation.getMaps().get(0).getName() +