Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add weighted voting pool support #1403

Merged
merged 1 commit into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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