Merge pull request #5 from Pablete1234/dynamic-rot

Fix dynamic rotations, make use of guice
This commit is contained in:
ShinyDialga 2017-03-27 20:56:47 -05:00 committed by GitHub
commit c84a9530ab
11 changed files with 111 additions and 100 deletions

View File

@ -40,7 +40,6 @@ import tc.oc.pgm.match.MatchManager;
import tc.oc.pgm.match.MatchPlayer;
import tc.oc.pgm.polls.PollListener;
import tc.oc.pgm.polls.PollManager;
import tc.oc.pgm.rotation.DynamicRotationChangeListener;
import tc.oc.pgm.start.StartCommands;
import tc.oc.pgm.tablist.MatchTabManager;
import tc.oc.pgm.timelimit.TimeLimitCommands;
@ -200,7 +199,6 @@ public final class PGM extends JavaPlugin {
this.registerEvents(new CraftingProtect());
this.registerEvents(new ObjectivesFireworkListener());
this.registerEvents(new ItemTransferListener());
this.registerEvents(new DynamicRotationChangeListener());
}
public void registerEvents(Listener listener) {

View File

@ -4,6 +4,7 @@ import tc.oc.commons.bukkit.chat.FlairRenderer;
import tc.oc.commons.bukkit.nick.UsernameRenderer;
import tc.oc.commons.core.inject.HybridManifest;
import tc.oc.commons.core.plugin.PluginFacetBinder;
import tc.oc.minecraft.api.event.ListenerBinder;
import tc.oc.pgm.analytics.MatchAnalyticsManifest;
import tc.oc.pgm.antigrief.DefuseListener;
import tc.oc.pgm.chat.MatchFlairRenderer;
@ -33,6 +34,7 @@ import tc.oc.pgm.match.MatchPlayerEventRouter;
import tc.oc.pgm.module.MatchModulesManifest;
import tc.oc.pgm.mutation.command.MutationCommands;
import tc.oc.pgm.restart.RestartListener;
import tc.oc.pgm.rotation.DynamicRotationListener;
import tc.oc.pgm.settings.Settings;
import tc.oc.pgm.spawns.states.State;
import tc.oc.pgm.tnt.license.LicenseBroker;
@ -65,6 +67,7 @@ public final class PGMManifest extends HybridManifest {
bind(MapLibrary.class).to(MapLibraryImpl.class);
bind(MapLoader.class).to(MapLoaderImpl.class);
new ListenerBinder(binder()).bindListener().to(DynamicRotationListener.class);
// Tourney needs this
expose(MapLibrary.class);

View File

@ -2,14 +2,11 @@ package tc.oc.pgm.commands;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Lists;
import com.sk89q.bukkit.util.BukkitWrappedCommandSender;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
@ -32,20 +29,17 @@ import tc.oc.commons.bukkit.nick.UsernameRenderer;
import tc.oc.commons.core.chat.Audience;
import tc.oc.commons.core.chat.Component;
import tc.oc.commons.core.chat.Components;
import tc.oc.pgm.Config;
import tc.oc.pgm.PGM;
import tc.oc.pgm.PGMTranslations;
import tc.oc.pgm.ffa.FreeForAllModule;
import tc.oc.pgm.map.Contributor;
import tc.oc.pgm.map.MapInfo;
import tc.oc.pgm.map.PGMMap;
import tc.oc.pgm.match.MatchManager;
import tc.oc.pgm.match.Party;
import tc.oc.pgm.modules.InfoModule;
import tc.oc.pgm.rotation.RotationManager;
import tc.oc.pgm.rotation.RotationProviderInfo;
import tc.oc.pgm.rotation.RotationState;
import tc.oc.pgm.teams.TeamFactory;
import tc.oc.pgm.teams.TeamModule;
public class MapCommands {
@Command(
@ -234,17 +228,20 @@ public class MapCommands {
@CommandPermissions("pgm.rotation.list")
public static void rotations(final CommandContext args, final CommandSender sender) throws CommandException {
RotationManager manager = PGM.getMatchManager().getRotationManager();
Map<String, RotationState> rotations = manager.getRotations();
List<RotationProviderInfo> rotations = manager.getProviders();
int page = args.getFlagInteger('p', 1);
new PrettyPaginatedResult<String>(PGMTranslations.get().t("command.map.rotationList.title", sender)) {
@Override public String format(String rotationName, int index) {
int activation = Config.getConfiguration().getInt("rotation.providers.file." + rotationName + ".count");
boolean current = rotationName.equalsIgnoreCase(PGM.getMatchManager().getRotationManager().getCurrentRotationName());
return (current ? ChatColor.GOLD + "\u0187 " : "") + (index % 2 == 0 ? ChatColor.AQUA : ChatColor.DARK_AQUA) + rotationName + (activation > 0 ? ChatColor.GRAY + " " + PGMTranslations.get().t("command.map.rotationList.activatesWith", sender, ChatColor.RED + "" + activation + ChatColor.GRAY) : "");
new PrettyPaginatedResult<RotationProviderInfo>(PGMTranslations.get().t("command.map.rotationList.title", sender)) {
@Override public String format(RotationProviderInfo rotationInfo, int index) {
boolean current = manager.getCurrentRotationName().equals(rotationInfo.name);
int count = rotationInfo.count;
return (current ? ChatColor.GOLD : ChatColor.GRAY) + " \u25ba " +
(index % 2 == 0 ? ChatColor.AQUA : ChatColor.DARK_AQUA) + rotationInfo.name +
(count > 0 ? ChatColor.GRAY + " " +
PGMTranslations.get().t("command.map.rotationList.activatesWith", sender,
ChatColor.RED + "" + count + ChatColor.GRAY) : "");
}
}.display(new BukkitWrappedCommandSender(sender), Lists.newArrayList(rotations.keySet()), page);
}.display(new BukkitWrappedCommandSender(sender), rotations, page);
}
@Command(

View File

@ -133,8 +133,6 @@ public class MapModuleContext extends ModuleContext<MapModule, MapScoped> {
public Integer playerLimitAverage() {
Range<Integer> lims = playerLimits();
int sum = lims.lowerEndpoint() + lims.upperEndpoint();
return ((Double) Math.floor(sum/2)).intValue();
return (lims.lowerEndpoint() + lims.upperEndpoint()) / 2;
}
}

View File

@ -1,68 +0,0 @@
package tc.oc.pgm.rotation;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.chat.TranslatableComponent;
import org.bukkit.configuration.Configuration;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import tc.oc.commons.bukkit.chat.HeaderComponent;
import tc.oc.commons.core.chat.Component;
import tc.oc.pgm.Config;
import tc.oc.pgm.PGM;
import tc.oc.pgm.cycle.CycleMatchModule;
import tc.oc.pgm.events.MatchEndEvent;
import tc.oc.pgm.match.Match;
public class DynamicRotationChangeListener implements Listener {
@EventHandler
public void onMatchEnd(MatchEndEvent event) {
RotationManager rotationManager = PGM.getMatchManager().getRotationManager();
// Ignore if dynamic rotations are disabled or if there is only one rotation available
if (!Config.getConfiguration().getBoolean("rotation.dynamic") || rotationManager.getRotations().size() == 1) return;
// Number of players we can assume is active
int playersOnline = event.getMatch().getServer().getOnlinePlayers().size();
// Get appropriate rotation
RotationCategory appr = getAppropriateRotationCategory(playersOnline, rotationManager);
if (appr != null && !rotationManager.getCurrentRotationName().equals(appr.toString().toLowerCase())) {
rotationManager.setRotation(appr.toString().toLowerCase(), rotationManager.getRotation(appr.toString().toLowerCase()));
rotationManager.setCurrentRotationName(appr.toString().toLowerCase());
CycleMatchModule cmm = event.getMatch().needMatchModule(CycleMatchModule.class);
cmm.startCountdown(cmm.getConfig().countdown());
PGM.get().getLogger().info("[Dynamic Rotations] Changing to \"" + appr.toString().toLowerCase() + "\" rotation...");
sendRotationChangeMessage(event.getMatch());
}
}
/**
* Returns appropriate rotation looking at how many players (participating) are online.
*
* @param players Current participant player count.
* @param rotationManager The {@link RotationManager}
* @return any of {@link RotationCategory}
*/
private RotationCategory getAppropriateRotationCategory(int players, RotationManager rotationManager) {
Configuration config = Config.getConfiguration();
int medium = config.getInt("rotation.providers.file.medium.count");
int mega = config.getInt("rotation.providers.file.mega.count");
if (players > medium && players <= mega && rotationManager.getRotation("medium") != null) return RotationCategory.MEDIUM;
if (players > mega && rotationManager.getRotation("mega") != null) return RotationCategory.MEGA;
return RotationCategory.MINI;
}
private void sendRotationChangeMessage(Match match) {
match.sendMessage(new HeaderComponent(ChatColor.RED));
match.sendMessage(new Component(new TranslatableComponent("rotation.change.broadcast.title"), ChatColor.GOLD));
match.sendMessage(new Component(new TranslatableComponent("rotation.change.broadcast.info"), ChatColor.YELLOW));
match.sendMessage(new HeaderComponent(ChatColor.RED));
}
}

View File

@ -0,0 +1,73 @@
package tc.oc.pgm.rotation;
import com.google.inject.Inject;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.TranslatableComponent;
import org.bukkit.configuration.Configuration;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import tc.oc.api.bukkit.users.OnlinePlayers;
import tc.oc.commons.bukkit.chat.Audiences;
import tc.oc.commons.bukkit.chat.HeaderComponent;
import tc.oc.commons.core.chat.Audience;
import tc.oc.commons.core.chat.Component;
import tc.oc.commons.core.logging.Loggers;
import tc.oc.commons.core.plugin.PluginFacet;
import tc.oc.pgm.PGM;
import tc.oc.pgm.events.MatchEndEvent;
import java.util.logging.Logger;
public class DynamicRotationListener implements PluginFacet, Listener {
private final Logger logger;
private final Audiences audiences;
private final OnlinePlayers players;
private final ConfigurationSection config;
@Inject DynamicRotationListener(Loggers loggers, Audiences audiences, OnlinePlayers players, Configuration config) {
this.logger = loggers.get(getClass());
this.audiences = audiences;
this.players = players;
this.config = config.getConfigurationSection("rotation");
}
@EventHandler(priority = EventPriority.MONITOR)
public void onMatchEnd(MatchEndEvent event) {
RotationManager rotationManager = PGM.getMatchManager().getRotationManager();
// Ignore if dynamic rotations are disabled or if there is only one rotation available
if (!config.getBoolean("dynamic", false) || rotationManager.getRotations().size() <= 1) return;
int playerCount = players.count();
// Get appropriate rotation
RotationProviderInfo rotation = rotationManager.getProviders().stream()
.filter(info -> playerCount >= info.count).findFirst().orElse(null);
if (rotation == null) {
logger.warning("No valid rotation was found to accommodate " + playerCount + " players. Missing fallback?");
} else {
RotationState rotState = rotation.provider.getRotation(rotation.name);
if (rotState == null) {
logger.warning("'" + rotation.name + "' rotation provider doesn't have a rotation with it's own name");
} else if (!rotationManager.getCurrentRotationName().equals(rotation.name)) {
rotationManager.setRotation(rotation.name, rotState);
rotationManager.setCurrentRotationName(rotation.name);
logger.info("Changing to \"" + rotation.name + "\" rotation...");
sendRotationChangeMessage(audiences.localServer());
}
}
}
private void sendRotationChangeMessage(Audience audience) {
audience.sendMessage(new HeaderComponent(ChatColor.RED));
audience.sendMessage(new Component(new TranslatableComponent("rotation.change.broadcast.title"), ChatColor.GOLD));
audience.sendMessage(new Component(new TranslatableComponent("rotation.change.broadcast.info"), ChatColor.YELLOW));
audience.sendMessage(new HeaderComponent(ChatColor.RED));
}
}

View File

@ -1,5 +0,0 @@
package tc.oc.pgm.rotation;
public enum RotationCategory {
MINI, MEDIUM, MEGA
}

View File

@ -115,6 +115,10 @@ public class RotationManager {
}
return null;
}
public @Nonnull List<RotationProviderInfo> getProviders() {
return ImmutableList.copyOf(this.providers);
}
public void addProvider(@Nonnull RotationProvider provider, @Nonnull String name, int priority, int count) {
Preconditions.checkNotNull(provider, "rotation provider");

View File

@ -29,4 +29,15 @@ public class RotationProviderInfo implements Comparable<RotationProviderInfo> {
}
return c;
}
@Override
public String toString() {
return "RotationProviderInfo{" +
"provider=" + provider.getRotations() +
", priority=" + priority +
", count=" + count +
", name='" + name + '\'' +
'}';
}
}

View File

@ -5,6 +5,7 @@ import java.util.List;
import javax.annotation.Nonnull;
import tc.oc.commons.core.util.Lazy;
import tc.oc.pgm.map.PGMMap;
import com.google.common.base.Preconditions;
@ -40,18 +41,16 @@ public final class RotationState {
return this.maps;
}
private Lazy<Integer> averageNeededPlayers = Lazy.from(() ->
(int) getMaps().stream().mapToInt(map -> map.getContext().playerLimitAverage()).average().orElse(0));
/**
* Gets the approximate number of players supposed to be playing the rotation maps.
* @return Integer with average size of teams over all maps
*/
public @Nonnull Integer getAverageNeededPlayers() {
List<Integer> players = new ArrayList<>();
int total = 0;
getMaps().stream().forEach(m -> players.add(m.getContext().playerLimitAverage()));
for (int pl : players) { total += pl; }
return ((Double) Math.floor(total / players.size())).intValue();
return averageNeededPlayers.get();
}
/**

View File

@ -79,6 +79,7 @@ environment:
ranked: false
rotation:
dynamic: false
default-name: default
initial-wait: 20000
providers: {}