Make map context a soft reference, and keep a persistent context (#79)
This commit is contained in:
parent
1450849c34
commit
6cf7610fad
|
@ -174,7 +174,7 @@ public class MapCommands implements Commands {
|
||||||
map = CommandUtils.getMatch(sender).getMap();
|
map = CommandUtils.getMatch(sender).getMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
final InfoModule infoModule = map.getContext().needModule(InfoModule.class);
|
final InfoModule infoModule = map.getPersistentContext().getInfoModule();
|
||||||
final MapInfo mapInfo = infoModule.getMapInfo();
|
final MapInfo mapInfo = infoModule.getMapInfo();
|
||||||
|
|
||||||
audience.sendMessage(mapInfo.getFormattedMapTitle());
|
audience.sendMessage(mapInfo.getFormattedMapTitle());
|
||||||
|
@ -243,16 +243,7 @@ public class MapCommands implements Commands {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int maxPlayers = map.getContext()
|
int maxPlayers = map.getPersistentContext().playerLimits().upperEndpoint();
|
||||||
.features()
|
|
||||||
.all(TeamFactory.class)
|
|
||||||
.mapToInt(TeamFactory::getMaxPlayers)
|
|
||||||
.sum();
|
|
||||||
|
|
||||||
FreeForAllModule ffam = map.getContext().getModule(FreeForAllModule.class);
|
|
||||||
if(ffam != null) {
|
|
||||||
maxPlayers += ffam.getOptions().maxPlayers;
|
|
||||||
}
|
|
||||||
|
|
||||||
audience.sendMessage(new Component(
|
audience.sendMessage(new Component(
|
||||||
mapInfoLabel("command.map.mapInfo.playerLimit"),
|
mapInfoLabel("command.map.mapInfo.playerLimit"),
|
||||||
|
@ -261,7 +252,7 @@ public class MapCommands implements Commands {
|
||||||
|
|
||||||
if(sender.hasPermission(Permissions.MAPDEV)) {
|
if(sender.hasPermission(Permissions.MAPDEV)) {
|
||||||
audience.sendMessage(new Component(mapInfoLabel("command.map.mapInfo.genre"), new Component(mapInfo.getLocalizedGenre(), ChatColor.GOLD)));
|
audience.sendMessage(new Component(mapInfoLabel("command.map.mapInfo.genre"), new Component(mapInfo.getLocalizedGenre(), ChatColor.GOLD)));
|
||||||
audience.sendMessage(new Component(mapInfoLabel("command.map.mapInfo.proto"), new Component(map.getContext().getProto().toString(), ChatColor.GOLD)));
|
audience.sendMessage(new Component(mapInfoLabel("command.map.mapInfo.proto"), new Component(map.getPersistentContext().getProto().toString(), ChatColor.GOLD)));
|
||||||
audience.sendMessage(new Component(mapInfoLabel("command.map.mapInfo.folder"), new Component(map.getFolder().getRelativePath().toString(), ChatColor.GOLD)));
|
audience.sendMessage(new Component(mapInfoLabel("command.map.mapInfo.folder"), new Component(map.getFolder().getRelativePath().toString(), ChatColor.GOLD)));
|
||||||
audience.sendMessage(new Component(mapInfoLabel("command.map.mapInfo.source"), new Component(map.getSource().getPath().toString(), ChatColor.GOLD)));
|
audience.sendMessage(new Component(mapInfoLabel("command.map.mapInfo.source"), new Component(map.getSource().getPath().toString(), ChatColor.GOLD)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,11 +120,11 @@ public class CycleMatchModule extends MatchModule implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public int min_players() {
|
@Override public int min_players() {
|
||||||
return nextMap.getContext().playerLimits().lowerEndpoint();
|
return nextMap.getPersistentContext().playerLimits().lowerEndpoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public int max_players() {
|
@Override public int max_players() {
|
||||||
return nextMap.getContext().playerLimits().upperEndpoint();
|
return nextMap.getPersistentContext().playerLimits().upperEndpoint();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
|
|
|
@ -59,6 +59,7 @@ import tc.oc.pgm.map.MapConfiguration;
|
||||||
import tc.oc.pgm.map.MapDefinition;
|
import tc.oc.pgm.map.MapDefinition;
|
||||||
import tc.oc.pgm.map.MapLibrary;
|
import tc.oc.pgm.map.MapLibrary;
|
||||||
import tc.oc.pgm.map.MapLogRecord;
|
import tc.oc.pgm.map.MapLogRecord;
|
||||||
|
import tc.oc.pgm.map.MapModuleContext;
|
||||||
import tc.oc.pgm.map.MapNotFoundException;
|
import tc.oc.pgm.map.MapNotFoundException;
|
||||||
import tc.oc.pgm.map.PGMMap;
|
import tc.oc.pgm.map.PGMMap;
|
||||||
import tc.oc.pgm.match.Match;
|
import tc.oc.pgm.match.Match;
|
||||||
|
@ -205,7 +206,10 @@ public class MapDevelopmentCommands implements Commands {
|
||||||
final Optional<String> typeFilter = CommandUtils.flag(args, 't').map(String::toLowerCase);
|
final Optional<String> typeFilter = CommandUtils.flag(args, 't').map(String::toLowerCase);
|
||||||
final Optional<String> idFilter = CommandUtils.flag(args, 'i').map(String::toLowerCase);
|
final Optional<String> idFilter = CommandUtils.flag(args, 'i').map(String::toLowerCase);
|
||||||
|
|
||||||
Stream<? extends FeatureDefinition> features = map.getContext().features().all();
|
MapModuleContext context = map.getContext().orElseThrow(() ->
|
||||||
|
new IllegalStateException("The map modules are currently unloaded."));
|
||||||
|
|
||||||
|
Stream<? extends FeatureDefinition> features = context.features().all();
|
||||||
if(typeFilter.isPresent()) {
|
if(typeFilter.isPresent()) {
|
||||||
features = features.filter(f -> f.inspectType().toLowerCase().contains(typeFilter.get()));
|
features = features.filter(f -> f.inspectType().toLowerCase().contains(typeFilter.get()));
|
||||||
}
|
}
|
||||||
|
@ -222,7 +226,7 @@ public class MapDevelopmentCommands implements Commands {
|
||||||
feature.inspectIdentity().ifPresent(id -> c.extra(" ").extra(new Component(id, ChatColor.YELLOW)));
|
feature.inspectIdentity().ifPresent(id -> c.extra(" ").extra(new Component(id, ChatColor.YELLOW)));
|
||||||
|
|
||||||
if(locate) {
|
if(locate) {
|
||||||
final Element element = map.getContext().features().definitionNode(feature);
|
final Element element = context.features().definitionNode(feature);
|
||||||
if(element != null) {
|
if(element != null) {
|
||||||
c.extra(" ").extra(new Component(new Node(element).describeWithLocation(), ChatColor.DARK_AQUA));
|
c.extra(" ").extra(new Component(new Node(element).describeWithLocation(), ChatColor.DARK_AQUA));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package tc.oc.pgm.map;
|
package tc.oc.pgm.map;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.ref.SoftReference;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -40,6 +41,7 @@ public class MapDefinition {
|
||||||
|
|
||||||
@Inject private MapConfiguration configuration;
|
@Inject private MapConfiguration configuration;
|
||||||
@Inject private Provider<MapModuleContext> contextProvider;
|
@Inject private Provider<MapModuleContext> contextProvider;
|
||||||
|
@Inject private Provider<MapPersistentContext> persistentContextProvider;
|
||||||
@Inject private ExceptionHandler exceptionHandler;
|
@Inject private ExceptionHandler exceptionHandler;
|
||||||
@Inject private MapInjectionScope mapInjectionScope;
|
@Inject private MapInjectionScope mapInjectionScope;
|
||||||
|
|
||||||
|
@ -50,7 +52,8 @@ public class MapDefinition {
|
||||||
|
|
||||||
private final MapFolder folder;
|
private final MapFolder folder;
|
||||||
|
|
||||||
protected @Nullable MapModuleContext context;
|
protected @Nullable SoftReference<MapModuleContext> context;
|
||||||
|
private @Nullable MapPersistentContext persistentContext;
|
||||||
|
|
||||||
protected MapDefinition(MapFolder folder) {
|
protected MapDefinition(MapFolder folder) {
|
||||||
this.folder = folder;
|
this.folder = folder;
|
||||||
|
@ -81,20 +84,29 @@ public class MapDefinition {
|
||||||
return context != null;
|
return context != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapModuleContext getContext() {
|
public Optional<MapModuleContext> getContext() {
|
||||||
if(context == null) {
|
if(context == null) {
|
||||||
throw new IllegalStateException("Map is not loaded: " + this);
|
throw new IllegalStateException("Map is not loaded: " + this);
|
||||||
}
|
}
|
||||||
return context;
|
return Optional.ofNullable(context.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapPersistentContext getPersistentContext() {
|
||||||
|
if(persistentContext == null) {
|
||||||
|
throw new IllegalStateException("Map is not loaded: " + this);
|
||||||
|
}
|
||||||
|
return persistentContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean shouldReload() {
|
public boolean shouldReload() {
|
||||||
if(context == null) return true;
|
if(context == null) return true;
|
||||||
if(!configuration.autoReload()) return false;
|
if(!configuration.autoReload()) return false;
|
||||||
if(context.loadedFiles().isEmpty()) return configuration.reloadWhenError();
|
MapModuleContext mapContext = context.get();
|
||||||
|
if(mapContext == null) return true;
|
||||||
|
if(mapContext.loadedFiles().isEmpty()) return configuration.reloadWhenError();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for(Map.Entry<Path, HashCode> loaded : context.loadedFiles().entrySet()) {
|
for(Map.Entry<Path, HashCode> loaded : mapContext.loadedFiles().entrySet()) {
|
||||||
HashCode latest = Files.hash(loaded.getKey().toFile(), Hashing.sha256());
|
HashCode latest = Files.hash(loaded.getKey().toFile(), Hashing.sha256());
|
||||||
if(!latest.equals(loaded.getValue())) return true;
|
if(!latest.equals(loaded.getValue())) return true;
|
||||||
}
|
}
|
||||||
|
@ -116,7 +128,8 @@ public class MapDefinition {
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!newContext.hasErrors()) {
|
if(!newContext.hasErrors()) {
|
||||||
this.context = newContext;
|
this.context = new SoftReference<>(newContext);
|
||||||
|
this.persistentContext = newContext.asCurrentScope(persistentContextProvider::get);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package tc.oc.pgm.map;
|
||||||
|
|
||||||
|
import com.google.common.collect.Range;
|
||||||
|
import tc.oc.api.docs.SemanticVersion;
|
||||||
|
import tc.oc.pgm.map.inject.MapScoped;
|
||||||
|
import tc.oc.pgm.modules.InfoModule;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a replacement for classes that need information from MapModuleContext to use. MapModuleContext will not be
|
||||||
|
* guaranteed to be available if a match isn't being played for the map, but MapPersistentContext will always contain
|
||||||
|
* basic information required to reference the map (like map name, authors, or player amount).
|
||||||
|
*/
|
||||||
|
@MapScoped
|
||||||
|
public class MapPersistentContext {
|
||||||
|
|
||||||
|
@Inject private @MapProto SemanticVersion proto;
|
||||||
|
@Inject private InfoModule infoModule;
|
||||||
|
private Range<Integer> playerLimits;
|
||||||
|
private MapDocument apiDocument;
|
||||||
|
|
||||||
|
@Inject public MapPersistentContext(MapModuleContext context) {
|
||||||
|
this.playerLimits = context.playerLimits();
|
||||||
|
this.apiDocument = context.apiDocument();
|
||||||
|
}
|
||||||
|
|
||||||
|
public MapDocument apiDocument() {
|
||||||
|
return apiDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SemanticVersion getProto() {
|
||||||
|
return proto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Range<Integer> playerLimits() {
|
||||||
|
return this.playerLimits;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer playerLimitAverage() {
|
||||||
|
Range<Integer> lims = playerLimits();
|
||||||
|
return (lims.lowerEndpoint() + lims.upperEndpoint()) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
public InfoModule getInfoModule() {
|
||||||
|
return infoModule;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -48,7 +48,7 @@ public class PGMMap extends MapDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapInfo getInfo() {
|
public MapInfo getInfo() {
|
||||||
return getContext().needModule(InfoModule.class).getMapInfo();
|
return getPersistentContext().getInfoModule().getMapInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapId getId() {
|
public MapId getId() {
|
||||||
|
@ -56,7 +56,7 @@ public class PGMMap extends MapDefinition {
|
||||||
}
|
}
|
||||||
|
|
||||||
public MapDoc getDocument() {
|
public MapDoc getDocument() {
|
||||||
return getContext().apiDocument();
|
return getPersistentContext().apiDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -165,7 +165,7 @@ public class MatchLoader implements MatchFinder {
|
||||||
* @param map Map to load.
|
* @param map Map to load.
|
||||||
*/
|
*/
|
||||||
private Match loadMatch(PGMMap map) throws Throwable {
|
private Match loadMatch(PGMMap map) throws Throwable {
|
||||||
return map.getContext().asCurrentScope(() -> {
|
return map.getContext().orElseThrow(MapNotFoundException::new).asCurrentScope(() -> {
|
||||||
final WorldManager worldManager = this.worldManager.get();
|
final WorldManager worldManager = this.worldManager.get();
|
||||||
final String worldName = Match.createSlug(matchCounter.get());
|
final String worldName = Match.createSlug(matchCounter.get());
|
||||||
final World world = worldManager.createWorld(worldName);
|
final World world = worldManager.createWorld(worldName);
|
||||||
|
|
|
@ -43,7 +43,7 @@ public final class RotationState {
|
||||||
|
|
||||||
|
|
||||||
private Lazy<Integer> averageNeededPlayers = Lazy.from(() ->
|
private Lazy<Integer> averageNeededPlayers = Lazy.from(() ->
|
||||||
(int) getMaps().stream().mapToInt(map -> map.getContext().playerLimitAverage()).average().orElse(0));
|
(int) getMaps().stream().mapToInt(map -> map.getPersistentContext().playerLimitAverage()).average().orElse(0));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the approximate number of players supposed to be playing the rotation maps.
|
* Gets the approximate number of players supposed to be playing the rotation maps.
|
||||||
|
|
Loading…
Reference in New Issue