Skip to content

Commit

Permalink
Implement PlaceholderAPI support
Browse files Browse the repository at this point in the history
  • Loading branch information
Redned235 committed Nov 10, 2024
1 parent dba73de commit b467bb6
Show file tree
Hide file tree
Showing 23 changed files with 354 additions and 44 deletions.
7 changes: 7 additions & 0 deletions module/placeholderapi-integration/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
repositories {
maven("https://repo.extendedclip.com/content/repositories/placeholderapi/")
}

dependencies {
compileOnly("me.clip:placeholderapi:2.11.6")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
package org.battleplugins.arena.module.placeholderapi;

import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.battleplugins.arena.Arena;
import org.battleplugins.arena.ArenaPlayer;
import org.battleplugins.arena.BattleArena;
import org.battleplugins.arena.competition.Competition;
import org.battleplugins.arena.competition.phase.CompetitionPhaseType;
import org.battleplugins.arena.resolver.Resolver;
import org.battleplugins.arena.resolver.ResolverKey;
import org.battleplugins.arena.resolver.ResolverKeys;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class BattleArenaExpansion extends PlaceholderExpansion {
private final BattleArena plugin;

public BattleArenaExpansion(BattleArena plugin) {
this.plugin = plugin;
}

@Override
public @NotNull String getIdentifier() {
return "ba";
}

@Override
public @NotNull String getAuthor() {
return "BattlePlugins";
}

@Override
public @NotNull String getVersion() {
return this.plugin.getPluginMeta().getVersion();
}

@Override
public @Nullable String onPlaceholderRequest(Player player, @NotNull String params) {
String[] split = params.split("_");

// No data for us to parse
if (split.length < 2) {
return null;
}

ArenaPlayer arenaPlayer = ArenaPlayer.getArenaPlayer(player);
if (arenaPlayer != null && params.startsWith("competition")) {
String placeholder = String.join("_", split).substring("competition_".length());

Resolver resolver = arenaPlayer.resolve();
ResolverKey<?> resolverKey = ResolverKeys.get(placeholder.replace("_", "-"));
if (resolverKey != null && resolver.has(resolverKey)) {
return resolver.resolveToString(resolverKey);
}
}

// If player is null or no other placeholder resolvers have made it to this point,
// handle more general placeholders

String arenaName = split[0];
Arena arena = this.plugin.getArena(arenaName);

// No arena, so not much we can do here
if (arena == null) {
return null;
}

// Remaining text in split array
String placeholder = String.join("_", split).substring(arenaName.length() + 1);
switch (placeholder) {
case "active_competitions": {
return String.valueOf(this.plugin.getCompetitions(arena).size());
}
case "online_players": {
int players = 0;
for (Competition<?> competition : this.plugin.getCompetitions(arena)) {
players += competition.getAlivePlayerCount() + competition.getSpectatorCount();
}

return String.valueOf(players);
}
case "alive_players": {
int online = 0;
for (Competition<?> competition : this.plugin.getCompetitions(arena)) {
online += competition.getAlivePlayerCount();
}

return String.valueOf(online);
}
case "spectators": {
int spectators = 0;
for (Competition<?> competition : this.plugin.getCompetitions(arena)) {
spectators += competition.getSpectatorCount();
}

return String.valueOf(spectators);
}
case "waiting_competitions": {
int waitingCompetitions = 0;
for (Competition<?> competition : this.plugin.getCompetitions(arena)) {
CompetitionPhaseType<?, ?> phase = competition.getPhase();
if (CompetitionPhaseType.WAITING.equals(phase)) {
waitingCompetitions++;
}
}
return String.valueOf(waitingCompetitions);
}
case "ingame_competitions": {
int ingameCompetitions = 0;
for (Competition<?> competition : this.plugin.getCompetitions(arena)) {
CompetitionPhaseType<?, ?> phase = competition.getPhase();
if (CompetitionPhaseType.INGAME.equals(phase)) {
ingameCompetitions++;
}
}
return String.valueOf(ingameCompetitions);
}
}

return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.battleplugins.arena.module.placeholderapi;

import org.battleplugins.arena.BattleArena;

public class PlaceholderApiContainer {
private final BattleArenaExpansion expansion;

public PlaceholderApiContainer(BattleArena plugin) {
this.expansion = new BattleArenaExpansion(plugin);
this.expansion.register();
}

public void disable() {
this.expansion.unregister();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.battleplugins.arena.module.placeholderapi;

import org.battleplugins.arena.event.BattleArenaPostInitializeEvent;
import org.battleplugins.arena.event.BattleArenaShutdownEvent;
import org.battleplugins.arena.module.ArenaModule;
import org.battleplugins.arena.module.ArenaModuleInitializer;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;

/**
* A module that allows for hooking into the PlaceholderAPI plugin.
*/
@ArenaModule(id = PlaceholderApiIntegration.ID, name = "PlaceholderAPI", description = "Adds support for hooking into the PlaceholderAPI plugin.", authors = "BattlePlugins")
public class PlaceholderApiIntegration implements ArenaModuleInitializer {
public static final String ID = "placeholderapi";

private PlaceholderApiContainer container;

@EventHandler
public void onPostInitialize(BattleArenaPostInitializeEvent event) {
// Check that we have Vault installed
if (!Bukkit.getServer().getPluginManager().isPluginEnabled("PlaceholderAPI")) {
event.getBattleArena().module(PlaceholderApiIntegration.ID).ifPresent(container ->
container.disable("PlaceholderAPI is required for the PlaceholderAPI integration module to work!")
);

return;
}

this.container = new PlaceholderApiContainer(event.getBattleArena());
}

@EventHandler
public void onShutdown(BattleArenaShutdownEvent event) {
if (this.container != null) {
this.container.disable();
}
}
}
8 changes: 7 additions & 1 deletion plugin/src/main/java/org/battleplugins/arena/Arena.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.battleplugins.arena.resolver.Resolver;
import org.battleplugins.arena.resolver.ResolverKeys;
import org.battleplugins.arena.resolver.ResolverProvider;
import org.battleplugins.arena.util.Describable;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.Nullable;

Expand All @@ -49,7 +50,7 @@
* active game actions will occur (i.e. game timer, score, etc.)
*/
@DocumentationSource("https://docs.battleplugins.org/books/user-guide/chapter/configuration")
public class Arena implements ArenaLike, ArenaListener, Resolvable, ConfigHolder {
public class Arena implements ArenaLike, ArenaListener, ConfigHolder, Resolvable, Describable {

@Scoped
private BattleArena plugin;
Expand Down Expand Up @@ -330,6 +331,11 @@ public final Arena getArena() {
return this;
}

@Override
public final String describe() {
return this.getName();
}

@Override
public Resolver resolve() {
return Resolver.builder()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void load() {

Bukkit.getPluginManager().registerEvents(arena, this.battleArena);

this.battleArena.arenas.put(arena.getName(), arena);
this.battleArena.arenas.put(arena.getName().toLowerCase(Locale.ROOT), arena);

// Register command
PluginCommand command = this.battleArena.getCommand(arena.getName().toLowerCase(Locale.ROOT));
Expand Down
8 changes: 4 additions & 4 deletions plugin/src/main/java/org/battleplugins/arena/BattleArena.java
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ void postInitialize() {

// Initialize events
for (Map.Entry<String, List<EventOptions>> entry : this.config.getEvents().entrySet()) {
Arena arena = this.arenas.get(entry.getKey());
Arena arena = this.getArena(entry.getKey());
if (arena == null) {
this.warn("Event {} does not have a valid arena!", entry.getKey());
continue;
Expand Down Expand Up @@ -283,7 +283,7 @@ public boolean isInArena(Player player) {
* @return the arena from the given name
*/
public Optional<Arena> arena(String name) {
return Optional.ofNullable(this.arenas.get(name));
return Optional.ofNullable(this.getArena(name));
}

/**
Expand All @@ -294,7 +294,7 @@ public Optional<Arena> arena(String name) {
*/
@Nullable
public Arena getArena(String name) {
return this.arenas.get(name);
return this.arenas.get(name.toLowerCase(Locale.ROOT));
}

/**
Expand Down Expand Up @@ -714,7 +714,7 @@ private void loadArenaMaps() {
}
});
} catch (IOException e) {
throw new RuntimeException("Error loading maps for arena " + arenaName, e);
throw new RuntimeException("Error loading maps for arena " + arena.getName(), e);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,20 @@ public interface Competition<T extends Competition<T>> extends CompetitionLike<T
*/
void leave(Player player, ArenaLeaveEvent.Cause cause);

/**
* Gets the amount of players currently in the competition.
*
* @return the amount of players currently in the competition
*/
int getAlivePlayerCount();

/**
* Gets the amount of spectators currently in the competition.
*
* @return the amount of spectators currently in the competition
*/
int getSpectatorCount();

/**
* Gets the maximum amount of players that can join this competition.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,16 @@ public final Set<ArenaPlayer> getPlayers() {
public final Set<ArenaPlayer> getSpectators() {
return Collections.unmodifiableSet(this.playersByRole.getOrDefault(PlayerRole.SPECTATING, Set.of()));
}

@Override
public final int getAlivePlayerCount() {
return this.getPlayers().size();
}

@Override
public final int getSpectatorCount() {
return this.getSpectators().size();
}

@Override
public final int getMaxPlayers() {
Expand Down Expand Up @@ -385,11 +395,13 @@ private int calculateMaxPlayers() {
@Override
public Resolver resolve() {
Resolver.Builder builder = this.arena.resolve().toBuilder()
.define(ResolverKeys.ALIVE_PLAYERS, ResolverProvider.simple(this.getAlivePlayerCount(), String::valueOf))
.define(ResolverKeys.COMPETITION, ResolverProvider.simple(this.getCompetition(), this.getMap()::getName))
.define(ResolverKeys.ONLINE_PLAYERS, ResolverProvider.simple(this.getPlayers().size(), String::valueOf))
.define(ResolverKeys.ONLINE_PLAYERS, ResolverProvider.simple(this.getAlivePlayerCount() + this.getSpectatorCount(), String::valueOf))
.define(ResolverKeys.MAP, ResolverProvider.simple(this.getMap(), CompetitionMap::getName))
.define(ResolverKeys.MAX_PLAYERS, ResolverProvider.simple(this.getMaxPlayers(), String::valueOf))
.define(ResolverKeys.PHASE, ResolverProvider.simple(this.getPhaseManager().getCurrentPhase(), p -> p.getType().getName()));
.define(ResolverKeys.PHASE, ResolverProvider.simple(this.getPhaseManager().getCurrentPhase(), p -> p.getType().getName()))
.define(ResolverKeys.SPECTATORS, ResolverProvider.simple(this.getSpectatorCount(), String::valueOf));

this.getVictoryManager().resolve().mergeInto(builder);
if (this.getPhaseManager().getCurrentPhase() instanceof LiveCompetitionPhase<?> phase) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package org.battleplugins.arena.competition.map;

import org.battleplugins.arena.util.Describable;

/**
* A map for a competition.
*/
public interface CompetitionMap {
public interface CompetitionMap extends Describable {

/**
* Gets the name of the map.
Expand All @@ -18,4 +20,9 @@ public interface CompetitionMap {
* @return the type of map
*/
MapType getType();

@Override
default String describe() {
return this.getName();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import org.battleplugins.arena.event.ArenaListener;
import org.battleplugins.arena.event.action.EventAction;
import org.battleplugins.arena.options.ArenaOptionType;
import org.battleplugins.arena.util.Describable;
import org.jetbrains.annotations.Nullable;

import java.util.List;
Expand All @@ -20,7 +21,7 @@
/**
* Represents the phase of a competition.
*/
public abstract class CompetitionPhase<T extends Competition<T>> implements CompetitionLike<T>, ArenaListener {
public abstract class CompetitionPhase<T extends Competition<T>> implements CompetitionLike<T>, ArenaListener, Describable {
@Id
private CompetitionPhaseType<T, CompetitionPhase<T>> type;

Expand Down Expand Up @@ -162,4 +163,9 @@ public final CompetitionPhase<T> getPreviousPhase() {
protected final void setPreviousPhase(CompetitionPhase<T> previousPhase) {
this.previousPhase = previousPhase;
}

@Override
public final String describe() {
return this.type.describe();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import org.battleplugins.arena.competition.phase.phases.IngamePhase;
import org.battleplugins.arena.competition.phase.phases.VictoryPhase;
import org.battleplugins.arena.competition.phase.phases.WaitingPhase;
import org.battleplugins.arena.util.Describable;
import org.jetbrains.annotations.Nullable;

import java.util.HashMap;
Expand All @@ -18,7 +19,7 @@
* @param <C> the type of competition
* @param <T> the type of competition phase
*/
public final class CompetitionPhaseType<C extends Competition<C>, T extends CompetitionPhase<C>> {
public final class CompetitionPhaseType<C extends Competition<C>, T extends CompetitionPhase<C>> implements Describable {
private static final Map<String, CompetitionPhaseType<?, ?>> PHASE_TYPES = new HashMap<>();

public static final CompetitionPhaseType<?, WaitingPhase<?>> WAITING = new CompetitionPhaseType("waiting", WaitingPhase.class);
Expand Down Expand Up @@ -53,6 +54,11 @@ public static <C extends Competition<C>, T extends CompetitionPhase<C>> Competit
return new CompetitionPhaseType<>(name, clazz);
}

@Override
public String describe() {
return this.getName();
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
Loading

0 comments on commit b467bb6

Please sign in to comment.