Skip to content

Commit

Permalink
Fix a few event bugs, add hunger-deplete option and top-team-stat sco…
Browse files Browse the repository at this point in the history
…reboard line creator
  • Loading branch information
Redned235 committed Jul 21, 2024
1 parent 7b30c27 commit 5b7f7b6
Show file tree
Hide file tree
Showing 14 changed files with 210 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ public class ScoreboardTemplate {
name = "lines",
description = "The lines to display on the scoreboard.",
contextProvider = ScoreboardLineCreatorContextProvider.class,
required = true)
required = true
)
private List<ScoreboardLineCreator> lines;

public Component getTitle() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ public interface ScoreboardLineCreator {
Map<String, Class<? extends ScoreboardLineCreator>> LINE_CREATORS = Map.of(
"simple", SimpleLineCreator.class,
"player-list", PlayerListLineCreator.class,
"top-stat", TopStatLineCreator.class
"top-stat", TopStatLineCreator.class,
"top-team-stat", TopTeamStatLineCreator.class
);

List<Component> createLines(ArenaPlayer player);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package org.battleplugins.arena.module.scoreboard.line;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.kyori.adventure.text.format.TextColor;
import org.battleplugins.arena.ArenaPlayer;
import org.battleplugins.arena.BattleArena;
import org.battleplugins.arena.competition.team.TeamManager;
import org.battleplugins.arena.config.ArenaOption;
import org.battleplugins.arena.stat.ArenaStat;
import org.battleplugins.arena.stat.ArenaStats;
import org.battleplugins.arena.stat.StatHolder;
import org.battleplugins.arena.team.ArenaTeam;
import org.battleplugins.arena.util.Version;

import java.awt.Color;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

public class TopTeamStatLineCreator implements ScoreboardLineCreator {

@ArenaOption(name = "max-entries", description = "The maximum number of entries to display on the scoreboard.", required = true)
private int maxEntries;

@ArenaOption(name = "stat", description = "The stat to display on the scoreboard.", required = true)
private String stat;

@ArenaOption(name = "stat-color", description = "The color of the stat.")
private Color color;

@ArenaOption(name = "ascending", description = "Whether to display the stat in ascending order.")
private boolean ascending;

@SuppressWarnings("unchecked")
@Override
public List<Component> createLines(ArenaPlayer player) {
ArenaStat<?> stat = ArenaStats.get(this.stat);
if (stat == null) {
return List.of();
}

if (!(stat.getDefaultValue() instanceof Number)) {
BattleArena.getInstance().warn("Stat {} is not a number. Unsure how to sort players in top stat line type.", stat.getName());
return List.of();
}

List<Component> lines = new ArrayList<>(this.maxEntries);
TeamManager teamManager = player.getCompetition().getTeamManager();
List<ArenaTeam> teams = teamManager.getTeams()
.stream()
.sorted((team1, team2) -> {
int value1 = statOrDefault(teamManager, team1, (ArenaStat<Number>) stat).intValue();
int value2 = statOrDefault(teamManager, team2, (ArenaStat<Number>) stat).intValue();
return this.ascending ? Integer.compare(value1, value2) : Integer.compare(value2, value1);
})
.toList();

for (ArenaTeam team : teams) {
if (teamManager.getPlayersOnTeam(team).isEmpty()) {
continue;
}

Component component;
TextColor color = team.getTextColor();
if (Version.getServerVersion().isLessThan("1.20.4")) {
component = Component.text(team.getName(), color);
} else {
component = team.getFormattedName();
}

TextColor statColor = this.color == null ? NamedTextColor.WHITE : TextColor.color(this.color.getRGB());
lines.add(Component.text("(" + statOrDefault(teamManager, team, (ArenaStat<Number>) stat) + ") ", statColor).append(component));
}

return lines;
}

private static Number statOrDefault(TeamManager manager, ArenaTeam team, ArenaStat<Number> stat) {
StatHolder stats = manager.getStats(team);
if (stats.stat(stat).isEmpty()) {
Set<ArenaPlayer> players = manager.getPlayersOnTeam(team);
int score = 0;
for (ArenaPlayer teamPlayer : players) {
score += teamPlayer.stat(stat).orElse(stat.getDefaultValue()).intValue();
}

return score;
} else {
return stats.stat(stat).orElse(stat.getDefaultValue());
}
}
}
18 changes: 18 additions & 0 deletions module/scoreboards/src/main/resources/scoreboards.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ templates:
- top-stat:
stat: kills
max-entries: 8
- simple:
lines:
- " "
- "<white>battleplugins.org"
ingame-top-team-kills:
title: "<gold>%arena%"
refresh-time: 1s
lines:
- simple:
lines:
- " "
- "<yellow>Map: <white>%map%"
- "<yellow>Time remaining: <white>%time_remaining_short%"
- " "
- "<yellow>Top teams:"
- top-team-stat:
stat: kills
max-entries: 8
- simple:
lines:
- " "
Expand Down
13 changes: 7 additions & 6 deletions plugin/src/main/java/org/battleplugins/arena/BattleArena.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public void onLoad() {

this.info("Loading BattleArena {} for {}", this.getPluginMeta().getVersion(), Version.getServerVersion());

this.loadConfig();
this.loadConfig(false);

Path dataFolder = this.getDataFolder().toPath();
this.arenasPath = dataFolder.resolve("arenas");
Expand Down Expand Up @@ -245,7 +245,7 @@ public void reload() {
this.disable();

// Reload the config
this.loadConfig();
this.loadConfig(true);

this.enable();

Expand Down Expand Up @@ -730,7 +730,7 @@ private void clearDynamicMaps() {
}
}

private void loadConfig() {
private void loadConfig(boolean reload) {
this.saveDefaultConfig();

File configFile = new File(this.getDataFolder(), "config.yml");
Expand All @@ -740,9 +740,10 @@ private void loadConfig() {
} catch (ParseException e) {
ParseException.handle(e);

this.error("Failed to load BattleArena configuration! Disabling plugin.");
this.getServer().getPluginManager().disablePlugin(this);
return;
this.error("Failed to load BattleArena configuration!");
if (!reload) {
this.getServer().getPluginManager().disablePlugin(this);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ private ArenaPlayer createPlayer(Player player) {

private int calculateMaxPlayers() {
Teams teams = this.arena.getTeams();
int teamAmount = teams.isNonTeamGame() ? teams.getTeamAmount().getMax() : teams.getAvailableTeams().size();
int teamAmount = teams.isNonTeamGame() ? teams.getTeamAmount().getMax() : this.teamManager.getTeams().size();
int teamSizeMax = teams.getTeamSize().getMax();
int maxPlayers;
if (teamSizeMax == Integer.MAX_VALUE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerInteractEvent;
Expand Down Expand Up @@ -146,6 +147,13 @@ public void onEntityDamage(EntityDamageByEntityEvent event) {
}
}

@ArenaEventHandler(priority = EventPriority.LOWEST)
public void onFoodLevelChange(FoodLevelChangeEvent event) {
if (!this.competition.option(ArenaOptionType.HUNGER_DEPLETE).map(BooleanArenaOption::isEnabled).orElse(true)) {
event.setCancelled(true);
}
}

@SuppressWarnings("unchecked")
@Override
public T getCompetition() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.battleplugins.arena.competition.team;

import org.battleplugins.arena.ArenaPlayer;
import org.battleplugins.arena.BattleArena;
import org.battleplugins.arena.competition.LiveCompetition;
import org.battleplugins.arena.competition.map.LiveCompetitionMap;
import org.battleplugins.arena.competition.map.options.Spawns;
import org.battleplugins.arena.competition.map.options.TeamSpawns;
import org.battleplugins.arena.options.Teams;
import org.battleplugins.arena.stat.StatHolder;
import org.battleplugins.arena.team.ArenaTeam;
Expand All @@ -28,8 +30,23 @@ public class TeamManager {
public TeamManager(LiveCompetition<?> competition) {
this.competition = competition;

for (ArenaTeam availableTeam : competition.getArena().getTeams().getAvailableTeams()) {
this.teams.put(availableTeam, new HashSet<>());
if (competition.getArena().getTeams().isNonTeamGame() || (competition.getMap().getSpawns() == null || competition.getMap().getSpawns().getTeamSpawns() == null)) {
for (ArenaTeam availableTeam : competition.getArena().getTeams().getAvailableTeams()) {
this.teams.put(availableTeam, new HashSet<>());
}

return;
}

for (Map.Entry<String, TeamSpawns> entry : competition.getMap().getSpawns().getTeamSpawns().entrySet()) {
String teamName = entry.getKey();
ArenaTeam team = BattleArena.getInstance().getTeams().getTeam(teamName);
if (team == null) {
BattleArena.getInstance().warn("Could not find team with name {} when loading {} for {}!", teamName, competition.getMap().getName(), competition.getArena().getName());
continue;
}

this.teams.put(team, new HashSet<>());
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,22 @@ public <T> T getStat(ArenaStat<T> stat) {
if (total == null) {
total = (Number) playerStat;
} else {
total = (Number) stat.getType().cast(total.doubleValue() + ((Number) playerStat).doubleValue());
Class<T> type = stat.getType();
if (type.equals(Integer.class)) {
total = total.intValue() + (Integer) playerStat;
} else if (type.equals(Double.class)) {
total = total.doubleValue() + (Double) playerStat;
} else if (type.equals(Float.class)) {
total = total.floatValue() + (Float) playerStat;
} else if (type.equals(Long.class)) {
total = total.longValue() + (Long) playerStat;
} else if (type.equals(Short.class)) {
total = total.shortValue() + (Short) playerStat;
} else if (type.equals(Byte.class)) {
total = total.byteValue() + (Byte) playerStat;
} else {
throw new IllegalArgumentException("Don't know how to accumulate type " + stat.getType());
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ private static void populateType(@Nullable Path sourceFile, Field field, ArenaOp
}
} else {
// Value is not a primitive, let's check to see if we have a provider for it
if (OBJECT_PROVIDERS.containsKey(type)) {
if (OBJECT_PROVIDERS.containsKey(type) && configuration.contains(name)) {
try {
field.set(instance, OBJECT_PROVIDERS.get(type).parse(configuration.get(name)));
} catch (ParseException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import org.battleplugins.arena.editor.ArenaEditorWizard;
import org.battleplugins.arena.editor.EditorContext;
import org.battleplugins.arena.team.ArenaTeam;
import org.battleplugins.arena.util.IntRange;
import org.battleplugins.arena.util.PositionWithRotation;
import org.bukkit.Location;
import org.bukkit.entity.Player;
Expand Down Expand Up @@ -91,7 +92,29 @@ public void addSpawn(String team, PositionWithRotation spawns) {
}

public boolean hasValidTeamSpawns() {
return this.getMissingTeams().isEmpty();
List<ArenaTeam> missingTeams = this.getMissingTeams();

// No missing teams - we don't need to check for anything further
if (missingTeams.isEmpty()) {
return true;
}

IntRange teamAmount = this.arena.getTeams().getTeamAmount();
if (teamAmount.getMax() == Integer.MAX_VALUE) {
// Check if we have the spawns for the minimum amount
int teamsWithSpawns = 0;
for (ArenaTeam availableTeam : this.arena.getTeams().getAvailableTeams()) {
if (this.spawns.containsKey(availableTeam.getName()) && !this.spawns.get(availableTeam.getName()).isEmpty()) {
teamsWithSpawns++;
}
}

return teamsWithSpawns >= teamAmount.getMin();
}

// We are not bounded by the maximum value, so
// each team must have a spawnpoint
return false;
}

public List<ArenaTeam> getMissingTeams() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ public <T extends Event & ArenaEvent> T callEvent(T event) {
private <T extends Event & ArenaEvent> void pollActions(T event, Competition<?> competition, Iterator<EventAction> iterator, Collection<ArenaPlayer> players) {
while (iterator.hasNext()) {
EventAction action = iterator.next();
if (action instanceof DelayAction delayAction) {
if (!Bukkit.isStopping() && action instanceof DelayAction delayAction) {
Bukkit.getScheduler().runTaskLater(BattleArena.getInstance(), () -> this.pollActions(event, competition, iterator, players), delayAction.getTicks());
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ public final class ArenaOptionType<T extends ArenaOption> {
public static final ArenaOptionType<BooleanArenaOption> ITEM_DROPS = new ArenaOptionType<>("item-drops", BooleanArenaOption::new);
public static final ArenaOptionType<BooleanArenaOption> KEEP_INVENTORY = new ArenaOptionType<>("keep-inventory", BooleanArenaOption::new);
public static final ArenaOptionType<BooleanArenaOption> KEEP_EXPERIENCE = new ArenaOptionType<>("keep-experience", BooleanArenaOption::new);
public static final ArenaOptionType<BooleanArenaOption> HUNGER_DEPLETE = new ArenaOptionType<>("hunger-deplete", BooleanArenaOption::new);
public static final ArenaOptionType<BooleanArenaOption> TEAM_SELECTION = new ArenaOptionType<>("team-selection", BooleanArenaOption::new);

public static final ArenaOptionType<EnumArenaOption<DamageOption>> DAMAGE_PLAYERS = new ArenaOptionType<>("damage-players", params -> new EnumArenaOption<>(params, DamageOption.class, "option"));
Expand Down
17 changes: 17 additions & 0 deletions plugin/src/main/java/org/battleplugins/arena/team/ArenaTeams.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.Color;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;

@DocumentationSource("https://docs.battleplugins.org/books/user-guide/page/teams")
public final class ArenaTeams implements Iterable<ArenaTeam> {
Expand All @@ -19,6 +21,21 @@ public final class ArenaTeams implements Iterable<ArenaTeam> {
@ArenaOption(name = "teams", description = "All of the registered teams.", required = true)
private List<ArenaTeam> teams;

public Optional<ArenaTeam> team(String name) {
return Optional.ofNullable(this.getTeam(name));
}

@Nullable
public ArenaTeam getTeam(String name) {
for (ArenaTeam team : this.teams) {
if (team.getName().equalsIgnoreCase(name)) {
return team;
}
}

return null;
}

@NotNull
@Override
public Iterator<ArenaTeam> iterator() {
Expand Down

0 comments on commit 5b7f7b6

Please sign in to comment.