Skip to content

Commit

Permalink
Add weighted voting pool support (#1403)
Browse files Browse the repository at this point in the history
Signed-off-by: Pablo Herrera <[email protected]>
  • Loading branch information
Pablete1234 authored Oct 2, 2024
1 parent dfa7853 commit 78df927
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 197 deletions.
181 changes: 75 additions & 106 deletions core/src/main/java/tc/oc/pgm/command/MapPoolCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,18 @@ public void pool(
int resultsPerPage = all ? maps.size() : 8;
int pages = all ? 1 : (maps.size() + resultsPerPage - 1) / resultsPerPage;

Component mapPoolComponent =
TextFormatter.paginate(
text()
.append(translatable("pool.name"))
.append(text(" (", NamedTextColor.DARK_AQUA))
.append(text(mapPool.getName(), NamedTextColor.AQUA))
.append(text(")", NamedTextColor.DARK_AQUA))
.build(),
page,
pages,
NamedTextColor.DARK_AQUA,
NamedTextColor.AQUA,
false);
Component mapPoolComponent = TextFormatter.paginate(
text()
.append(translatable("pool.name"))
.append(text(" (", NamedTextColor.DARK_AQUA))
.append(text(mapPool.getName(), NamedTextColor.AQUA))
.append(text(")", NamedTextColor.DARK_AQUA))
.build(),
page,
pages,
NamedTextColor.DARK_AQUA,
NamedTextColor.AQUA,
false);

Component title =
TextFormatter.horizontalLineHeading(source, mapPoolComponent, NamedTextColor.BLUE, 250);
Expand All @@ -96,7 +95,7 @@ public void pool(
if (chance && votes != null) {
double maxWeight = 0, currWeight;
for (MapInfo map : votes.getMaps()) {
chances.put(map, currWeight = votes.mapPicker.getWeight(null, map, votes.getMapScore(map)));
chances.put(map, currWeight = votes.mapPicker.getWeight(null, map, votes.getVoteData(map)));
maxWeight += currWeight;
}
double finalMaxWeight = maxWeight;
Expand All @@ -106,23 +105,19 @@ public void pool(
int nextPos = mapPool instanceof Rotation ? ((Rotation) mapPool).getNextPosition() : -1;

if (order && votes != null) {
maps =
maps.stream()
.sorted(
Comparator.comparingDouble(chance ? chances::get : votes::getMapScore).reversed())
.collect(Collectors.toList());
maps = maps.stream()
.sorted(Comparator.comparingDouble(chance ? chances::get : votes::getMapScore)
.reversed())
.collect(Collectors.toList());
}

new PrettyPaginatedComponentResults<MapInfo>(title, resultsPerPage) {
@Override
public Component format(MapInfo map, int index) {
index++;
TextComponent.Builder entry =
text()
.append(
text(
index + ". ",
nextPos == index ? NamedTextColor.DARK_AQUA : NamedTextColor.WHITE));
TextComponent.Builder entry = text()
.append(text(
index + ". ", nextPos == index ? NamedTextColor.DARK_AQUA : NamedTextColor.WHITE));
if (votes != null && scores)
entry.append(
text(SCORE_FORMAT.format(votes.getMapScore(map)) + " ", NamedTextColor.YELLOW));
Expand Down Expand Up @@ -156,45 +151,41 @@ public void pools(
int resultsPerPage = 8;
int pages = (mapPools.size() + resultsPerPage - 1) / resultsPerPage;

Component paginated =
TextFormatter.paginate(
translatable("pool.title"),
page,
pages,
NamedTextColor.DARK_AQUA,
NamedTextColor.AQUA,
true);
Component paginated = TextFormatter.paginate(
translatable("pool.title"),
page,
pages,
NamedTextColor.DARK_AQUA,
NamedTextColor.AQUA,
true);

Component formattedTitle =
TextFormatter.horizontalLineHeading(source, paginated, NamedTextColor.BLUE);

new PrettyPaginatedComponentResults<MapPool>(formattedTitle, resultsPerPage) {
@Override
public Component format(MapPool mapPool, int index) {
Component arrow =
text(
"» ",
poolManager.getActiveMapPool().equals(mapPool)
? NamedTextColor.GREEN
: NamedTextColor.WHITE);

Component maps =
text()
.append(text(" (", NamedTextColor.DARK_AQUA))
.append(translatable("map.title", NamedTextColor.DARK_GREEN))
.append(text(": ", NamedTextColor.DARK_GREEN))
.append(text(mapPool.getMaps().size(), NamedTextColor.WHITE))
.append(text(")", NamedTextColor.DARK_AQUA))
.build();

Component players =
text()
.append(text(" (", NamedTextColor.DARK_AQUA))
.append(translatable("match.info.players", NamedTextColor.AQUA))
.append(text(": ", NamedTextColor.AQUA))
.append(text(mapPool.getPlayers(), NamedTextColor.WHITE))
.append(text(")", NamedTextColor.DARK_AQUA))
.build();
Component arrow = text(
"» ",
poolManager.getActiveMapPool().equals(mapPool)
? NamedTextColor.GREEN
: NamedTextColor.WHITE);

Component maps = text()
.append(text(" (", NamedTextColor.DARK_AQUA))
.append(translatable("map.title", NamedTextColor.DARK_GREEN))
.append(text(": ", NamedTextColor.DARK_GREEN))
.append(text(mapPool.getMaps().size(), NamedTextColor.WHITE))
.append(text(")", NamedTextColor.DARK_AQUA))
.build();

Component players = text()
.append(text(" (", NamedTextColor.DARK_AQUA))
.append(translatable("match.info.players", NamedTextColor.AQUA))
.append(text(": ", NamedTextColor.AQUA))
.append(text(mapPool.getPlayers(), NamedTextColor.WHITE))
.append(text(")", NamedTextColor.DARK_AQUA))
.build();

return text()
.append(arrow)
Expand Down Expand Up @@ -223,11 +214,10 @@ public void setPool(
if (newPool == null) throw exception("pool.noPoolMatch");

if (newPool.equals(poolManager.getActiveMapPool())) {
sender.sendMessage(
translatable(
"pool.matching",
NamedTextColor.GRAY,
text(newPool.getName(), NamedTextColor.LIGHT_PURPLE)));
sender.sendMessage(translatable(
"pool.matching",
NamedTextColor.GRAY,
text(newPool.getName(), NamedTextColor.LIGHT_PURPLE)));
return;
}

Expand Down Expand Up @@ -268,17 +258,15 @@ public void skip(

((Rotation) pool).advance(positions);

Component message =
text()
.append(text("[", NamedTextColor.WHITE))
.append(translatable("pool.name", NamedTextColor.GOLD))
.append(text("] [", NamedTextColor.WHITE))
.append(text(pool.getName(), NamedTextColor.AQUA))
.append(text("]", NamedTextColor.WHITE))
.append(
translatable(
"pool.skip", NamedTextColor.GREEN, text(positions, NamedTextColor.AQUA)))
.build();
Component message = text()
.append(text("[", NamedTextColor.WHITE))
.append(translatable("pool.name", NamedTextColor.GOLD))
.append(text("] [", NamedTextColor.WHITE))
.append(text(pool.getName(), NamedTextColor.AQUA))
.append(text("]", NamedTextColor.WHITE))
.append(
translatable("pool.skip", NamedTextColor.GREEN, text(positions, NamedTextColor.AQUA)))
.build();

sender.sendMessage(message);
}
Expand All @@ -291,11 +279,10 @@ public void voteNext(
@Flag(value = "open", aliases = "o") boolean forceOpen,
@Argument("map") @FlagYielding MapInfo map) {
boolean voteResult = poll.toggleVote(map, player);
Component voteAction =
translatable(
voteResult ? "vote.for" : "vote.abstain",
voteResult ? NamedTextColor.GREEN : NamedTextColor.RED,
map.getStyledName(MapNameStyle.COLOR));
Component voteAction = translatable(
voteResult ? "vote.for" : "vote.abstain",
voteResult ? NamedTextColor.GREEN : NamedTextColor.RED,
map.getStyledName(MapNameStyle.COLOR));
player.sendMessage(voteAction);
poll.sendBook(player, forceOpen);
}
Expand All @@ -318,26 +305,12 @@ public void rot(
@Argument("page") @Default("1") @Range(min = "1") int page,
@Flag(value = "all", aliases = "a") boolean all,
String[] rawArgs) {
wrapLegacy(
"pool",
sender,
rawArgs,
() -> {
if (poolManager.getActiveMapPool().getType() != MapPoolType.ORDERED)
throw exception("pool.noRotation");

pool(
sender,
source,
poolManager,
page,
MapPoolType.ORDERED,
null,
false,
false,
false,
all);
});
wrapLegacy("pool", sender, rawArgs, () -> {
if (poolManager.getActiveMapPool().getType() != MapPoolType.ORDERED)
throw exception("pool.noRotation");

pool(sender, source, poolManager, page, MapPoolType.ORDERED, null, false, false, false, all);
});
}

@Command("rots [page]")
Expand Down Expand Up @@ -391,14 +364,10 @@ public void resetRot(
MapPool resetRot =
poolManager.getAppropriateDynamicPool(match).orElseThrow(() -> exception("pool.noDynamic"));

wrapLegacy(
"setpool",
sender,
rawArgs,
() -> {
if (resetRot.getType() != MapPoolType.ORDERED) throw exception("pool.noRotation");
setPool(sender, source, match, poolManager, resetRot, timeLimit, matchLimit);
});
wrapLegacy("setpool", sender, rawArgs, () -> {
if (resetRot.getType() != MapPoolType.ORDERED) throw exception("pool.noRotation");
setPool(sender, source, match, poolManager, resetRot, timeLimit, matchLimit);
});
}

private void wrapLegacy(String replace, Audience sender, String[] rawArgs, Runnable task) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import tc.oc.pgm.rotation.MapPoolManager;

public class DisabledMapPool extends MapPool {
DisabledMapPool(MapPoolManager manager, ConfigurationSection section, String name) {
super(null, name, manager, section);
DisabledMapPool(String name, MapPoolManager manager, ConfigurationSection section) {
super(null, name, manager, section, MapParser.parse(name, section));
}

@Override
Expand Down
101 changes: 101 additions & 0 deletions core/src/main/java/tc/oc/pgm/rotation/pools/MapParser.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package tc.oc.pgm.rotation.pools;

import static tc.oc.pgm.api.map.MapSource.DEFAULT_VARIANT;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.bukkit.configuration.ConfigurationSection;
import tc.oc.pgm.api.PGM;
import tc.oc.pgm.api.map.MapInfo;
import tc.oc.pgm.api.map.MapLibrary;
import tc.oc.pgm.api.map.VariantInfo;

public class MapParser {
private final MapLibrary maps = PGM.get().getMapLibrary();
private final String poolName;
private final List<String> variantIds;
private final ArrayList<MapInfo> mapList = new ArrayList<>();
private final Map<MapInfo, Double> weights = new HashMap<>();

public static MapParser parse(String poolName, ConfigurationSection section) {
var parser = new MapParser(poolName, section.getStringList("variants"));
if (section.contains("maps")) parser.parseSection(section, 1d);
return parser;
}

private MapParser(String poolName, List<String> variants) {
this.poolName = poolName;
if (variants != null) {
int def = variants.indexOf(DEFAULT_VARIANT);
if (def >= 0) variants = variants.subList(0, def);
if (variants.isEmpty()) variants = null;
}
this.variantIds = variants;
}

public List<MapInfo> getMaps() {
return mapList;
}

public double getWeight(MapInfo info) {
return weights.getOrDefault(info, 1d);
}

private void parseSection(ConfigurationSection parent, double parentWeight) {
Set<String> keys;
double weight;
if (parent.contains("maps")) {
keys = Set.of("maps");
weight = parent.getDouble("weight", parentWeight);
} else {
keys = parent.getKeys(false);
weight = parentWeight;
}
keys.forEach(k -> {
if (parent.isConfigurationSection(k)) parseSection(parent.getConfigurationSection(k), weight);
else parseMapList(parent.getStringList(k), weight);
});
}

private void parseMapList(List<String> mapNames, double weight) {
if (mapNames == null) return;

mapList.ensureCapacity(mapList.size() + mapNames.size());

for (String mapName : mapNames) {
MapInfo map = maps.getMap(mapName);
if (map != null) {
map = getVariant(map);
weights.computeIfAbsent(map, k -> {
mapList.add(k);
return weight;
});
} else {
PGM.get()
.getLogger()
.warning(
"[MapPool] [" + poolName + "] " + mapName + " not found in map repo. Ignoring...");
}
}
}

private MapInfo getVariant(MapInfo map) {
if (variantIds == null || !map.getVariantId().equals(DEFAULT_VARIANT)) return map;

Map<String, ? extends VariantInfo> variants = map.getVariants();
for (String varId : variantIds) {
VariantInfo variant = variants.get(varId);
if (variant == null) continue;
MapInfo variantMap = maps.getMapById(variant.getId());
if (variantMap != null) return variantMap;
// Should never happen
PGM.get()
.getLogger()
.warning("[MapPool] Failed to get map " + variant.getId() + ". Moving on...");
}
return map;
}
}
Loading

0 comments on commit 78df927

Please sign in to comment.