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();
|
||||
}
|
||||
|
||||
final InfoModule infoModule = map.getContext().needModule(InfoModule.class);
|
||||
final InfoModule infoModule = map.getPersistentContext().getInfoModule();
|
||||
final MapInfo mapInfo = infoModule.getMapInfo();
|
||||
|
||||
audience.sendMessage(mapInfo.getFormattedMapTitle());
|
||||
|
@ -243,16 +243,7 @@ public class MapCommands implements Commands {
|
|||
}
|
||||
}
|
||||
|
||||
int maxPlayers = map.getContext()
|
||||
.features()
|
||||
.all(TeamFactory.class)
|
||||
.mapToInt(TeamFactory::getMaxPlayers)
|
||||
.sum();
|
||||
|
||||
FreeForAllModule ffam = map.getContext().getModule(FreeForAllModule.class);
|
||||
if(ffam != null) {
|
||||
maxPlayers += ffam.getOptions().maxPlayers;
|
||||
}
|
||||
int maxPlayers = map.getPersistentContext().playerLimits().upperEndpoint();
|
||||
|
||||
audience.sendMessage(new Component(
|
||||
mapInfoLabel("command.map.mapInfo.playerLimit"),
|
||||
|
@ -261,7 +252,7 @@ public class MapCommands implements Commands {
|
|||
|
||||
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.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.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() {
|
||||
return nextMap.getContext().playerLimits().lowerEndpoint();
|
||||
return nextMap.getPersistentContext().playerLimits().lowerEndpoint();
|
||||
}
|
||||
|
||||
@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.MapLibrary;
|
||||
import tc.oc.pgm.map.MapLogRecord;
|
||||
import tc.oc.pgm.map.MapModuleContext;
|
||||
import tc.oc.pgm.map.MapNotFoundException;
|
||||
import tc.oc.pgm.map.PGMMap;
|
||||
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> 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()) {
|
||||
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)));
|
||||
|
||||
if(locate) {
|
||||
final Element element = map.getContext().features().definitionNode(feature);
|
||||
final Element element = context.features().definitionNode(feature);
|
||||
if(element != null) {
|
||||
c.extra(" ").extra(new Component(new Node(element).describeWithLocation(), ChatColor.DARK_AQUA));
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package tc.oc.pgm.map;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -40,6 +41,7 @@ public class MapDefinition {
|
|||
|
||||
@Inject private MapConfiguration configuration;
|
||||
@Inject private Provider<MapModuleContext> contextProvider;
|
||||
@Inject private Provider<MapPersistentContext> persistentContextProvider;
|
||||
@Inject private ExceptionHandler exceptionHandler;
|
||||
@Inject private MapInjectionScope mapInjectionScope;
|
||||
|
||||
|
@ -50,7 +52,8 @@ public class MapDefinition {
|
|||
|
||||
private final MapFolder folder;
|
||||
|
||||
protected @Nullable MapModuleContext context;
|
||||
protected @Nullable SoftReference<MapModuleContext> context;
|
||||
private @Nullable MapPersistentContext persistentContext;
|
||||
|
||||
protected MapDefinition(MapFolder folder) {
|
||||
this.folder = folder;
|
||||
|
@ -81,20 +84,29 @@ public class MapDefinition {
|
|||
return context != null;
|
||||
}
|
||||
|
||||
public MapModuleContext getContext() {
|
||||
public Optional<MapModuleContext> getContext() {
|
||||
if(context == null) {
|
||||
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() {
|
||||
if(context == null) return true;
|
||||
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 {
|
||||
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());
|
||||
if(!latest.equals(loaded.getValue())) return true;
|
||||
}
|
||||
|
@ -116,7 +128,8 @@ public class MapDefinition {
|
|||
});
|
||||
|
||||
if(!newContext.hasErrors()) {
|
||||
this.context = newContext;
|
||||
this.context = new SoftReference<>(newContext);
|
||||
this.persistentContext = newContext.asCurrentScope(persistentContextProvider::get);
|
||||
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() {
|
||||
return getContext().needModule(InfoModule.class).getMapInfo();
|
||||
return getPersistentContext().getInfoModule().getMapInfo();
|
||||
}
|
||||
|
||||
public MapId getId() {
|
||||
|
@ -56,7 +56,7 @@ public class PGMMap extends MapDefinition {
|
|||
}
|
||||
|
||||
public MapDoc getDocument() {
|
||||
return getContext().apiDocument();
|
||||
return getPersistentContext().apiDocument();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -165,7 +165,7 @@ public class MatchLoader implements MatchFinder {
|
|||
* @param map Map to load.
|
||||
*/
|
||||
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 String worldName = Match.createSlug(matchCounter.get());
|
||||
final World world = worldManager.createWorld(worldName);
|
||||
|
|
|
@ -43,7 +43,7 @@ public final class RotationState {
|
|||
|
||||
|
||||
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.
|
||||
|
|
Loading…
Reference in New Issue