Skip to content

Commit

Permalink
Add duels support and fix an issue with third party chat plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
Redned235 committed Jul 21, 2024
1 parent 5b7f7b6 commit 582432b
Show file tree
Hide file tree
Showing 13 changed files with 299 additions and 12 deletions.
Empty file added module/duels/build.gradle.kts
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package org.battleplugins.arena.module.duels;

import org.battleplugins.arena.Arena;
import org.battleplugins.arena.competition.Competition;
import org.battleplugins.arena.competition.JoinResult;
import org.battleplugins.arena.competition.LiveCompetition;
import org.battleplugins.arena.competition.PlayerRole;
import org.battleplugins.arena.competition.map.LiveCompetitionMap;
import org.battleplugins.arena.competition.map.MapType;
import org.battleplugins.arena.competition.phase.CompetitionPhaseType;
import org.battleplugins.arena.event.arena.ArenaCreateExecutorEvent;
import org.battleplugins.arena.event.player.ArenaPreJoinEvent;
import org.battleplugins.arena.messages.Messages;
import org.battleplugins.arena.module.ArenaModule;
import org.battleplugins.arena.module.ArenaModuleInitializer;
import org.battleplugins.arena.team.ArenaTeam;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.player.PlayerQuitEvent;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
* A module that adds duels to BattleArena.
*/
@ArenaModule(id = Duels.ID, name = "Duels", description = "Adds duels to BattleArena.", authors = "BattlePlugins")
public class Duels implements ArenaModuleInitializer {
public static final String ID = "duels";
public static final JoinResult PENDING_REQUEST = new JoinResult(false, DuelsMessages.PENDING_DUEL_REQUEST);

private final Map<UUID, UUID> duelRequests = new HashMap<>();

@EventHandler
public void onCreateExecutor(ArenaCreateExecutorEvent event) {
if (!event.getArena().isModuleEnabled(ID)) {
return;
}

event.registerSubExecutor(new DuelsExecutor(this, event.getArena()));
}

@EventHandler
public void onPlayerQuit(PlayerQuitEvent event) {
UUID requested = this.duelRequests.remove(event.getPlayer().getUniqueId());
Player requestedPlayer = Bukkit.getPlayer(requested);
if (requestedPlayer != null) {
DuelsMessages.DUEL_REQUESTED_CANCELLED_QUIT.send(requestedPlayer, event.getPlayer().getName());
}
}

@EventHandler(priority = EventPriority.HIGHEST)
public void onPreJoin(ArenaPreJoinEvent event) {
if (this.duelRequests.containsKey(event.getPlayer().getUniqueId())) {
event.setResult(PENDING_REQUEST);
}
}

public Map<UUID, UUID> getDuelRequests() {
return Map.copyOf(this.duelRequests);
}

public void addDuelRequest(UUID sender, UUID receiver) {
this.duelRequests.put(sender, receiver);
}

public void removeDuelRequest(UUID sender) {
this.duelRequests.remove(sender);
}

public void acceptDuel(Arena arena, Player player, Player target) {
LiveCompetition<?> competition = findOrJoinCompetition(arena);
if (competition == null) {
Messages.NO_OPEN_ARENAS.send(player);
Messages.NO_OPEN_ARENAS.send(target);
return;
}

// Non-team game - just join regularly and let game calculate team. Winner will be
// determined by the individual player who wins
if (arena.getTeams().isNonTeamGame()) {
competition.join(player, PlayerRole.PLAYING);
competition.join(target, PlayerRole.PLAYING);
} else {
ArenaTeam team1 = competition.getTeamManager().getTeams().iterator().next();
ArenaTeam team2 = competition.getTeamManager().getTeams().iterator().next();

competition.join(player, PlayerRole.PLAYING, team1);
competition.join(target, PlayerRole.PLAYING, team2);
}

// Force the game into the in-game state
competition.getPhaseManager().setPhase(CompetitionPhaseType.INGAME);
}

private LiveCompetition<?> findOrJoinCompetition(Arena arena) {
List<Competition<?>> openCompetitions = arena.getPlugin().getCompetitions(arena)
.stream()
.filter(competition -> competition instanceof LiveCompetition<?> liveCompetition
&& liveCompetition.getPhaseManager().getCurrentPhase().canJoin()
&& liveCompetition.getPlayers().isEmpty()
)
.toList();

// Ensure we have found an open competition
if (openCompetitions.isEmpty()) {
List<LiveCompetitionMap> dynamicMaps = arena.getPlugin().getMaps(arena)
.stream()
.filter(map -> map.getType() == MapType.DYNAMIC)
.toList();

if (dynamicMaps.isEmpty()) {
return null;
}

LiveCompetitionMap map = dynamicMaps.iterator().next();

LiveCompetition<?> competition = map.createDynamicCompetition(arena);
arena.getPlugin().addCompetition(arena, competition);
return competition;
} else {
return (LiveCompetition<?>) openCompetitions.iterator().next();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package org.battleplugins.arena.module.duels;

import org.battleplugins.arena.Arena;
import org.battleplugins.arena.ArenaPlayer;
import org.battleplugins.arena.BattleArena;
import org.battleplugins.arena.command.ArenaCommand;
import org.battleplugins.arena.command.SubCommandExecutor;
import org.battleplugins.arena.messages.Messages;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;

import java.util.Locale;
import java.util.UUID;

public class DuelsExecutor implements SubCommandExecutor {
private final Duels module;
private final Arena arena;
private final String parentCommand;

public DuelsExecutor(Duels module, Arena arena) {
this.module = module;
this.arena = arena;
this.parentCommand = arena.getName().toLowerCase(Locale.ROOT);
}

@ArenaCommand(commands = "duel", description = "Duel another player.", permissionNode = "duel")
public void duel(Player player, Player target) {
if (player.equals(target)) {
DuelsMessages.CANNOT_DUEL_SELF.send(player);
return;
}

ArenaPlayer arenaPlayer = ArenaPlayer.getArenaPlayer(player);
if (arenaPlayer != null) {
Messages.ALREADY_IN_ARENA.send(player);
return;
}

ArenaPlayer targetPlayer = ArenaPlayer.getArenaPlayer(target);
if (targetPlayer != null) {
Messages.ALREADY_IN_ARENA.send(player);
return;
}

if (this.module.getDuelRequests().containsKey(player.getUniqueId())) {
DuelsMessages.DUEL_REQUEST_ALREADY_SENT.send(player, this.parentCommand);
return;
}

DuelsMessages.DUEL_REQUEST_SENT.send(player, target.getName());
DuelsMessages.DUEL_REQUEST_RECEIVED.send(
target,
player.getName(),
this.parentCommand,
player.getName(),
this.parentCommand,
player.getName()
);

this.module.addDuelRequest(player.getUniqueId(), target.getUniqueId());
}

@ArenaCommand(commands = "duel", subCommands = "accept", description = "Accept a duel request.", permissionNode = "duel.accept")
public void acceptDuel(Player player, Player target) {
ArenaPlayer arenaPlayer = ArenaPlayer.getArenaPlayer(player);
if (arenaPlayer != null) {
Messages.ALREADY_IN_ARENA.send(player);
return;
}

UUID requestedId = this.module.getDuelRequests().get(target.getUniqueId());
if (requestedId == null) {
DuelsMessages.NO_DUEL_REQUESTS.send(player);
return;
}

if (!requestedId.equals(player.getUniqueId())) {
DuelsMessages.USER_DID_NOT_REQUEST.send(player, target.getName());
return;
}

DuelsMessages.DUEL_REQUEST_ACCEPTED.send(player, target.getName());
DuelsMessages.ACCEPTED_DUEL_REQUEST.send(target, player.getName());

this.module.removeDuelRequest(target.getUniqueId());

Bukkit.getScheduler().runTaskLater(BattleArena.getInstance(), () -> {
this.module.acceptDuel(this.arena, player, target);
}, 100);
}

@ArenaCommand(commands = "duel", subCommands = "deny", description = "Deny a duel request.", permissionNode = "duel.deny")
public void denyDuel(Player player, Player target) {
UUID requestedId = this.module.getDuelRequests().get(target.getUniqueId());
if (requestedId == null) {
DuelsMessages.NO_DUEL_REQUESTS.send(player);
return;
}

if (!requestedId.equals(player.getUniqueId())) {
DuelsMessages.USER_DID_NOT_REQUEST.send(player, target.getName());
return;
}

DuelsMessages.DUEL_REQUEST_DENIED.send(player, target.getName());
DuelsMessages.DENIED_DUEL_REQUEST.send(target, player.getName());

this.module.removeDuelRequest(target.getUniqueId());
}

@ArenaCommand(commands = "duel", subCommands = "cancel", description = "Cancel a duel request.", permissionNode = "duel.cancel")
public void cancelDuel(Player player) {
if (!this.module.getDuelRequests().containsKey(player.getUniqueId())) {
DuelsMessages.NO_DUEL_REQUESTS.send(player);
return;
}

UUID targetId = this.module.getDuelRequests().get(player.getUniqueId());
Player target = Bukkit.getServer().getPlayer(targetId);
if (target == null) {
// Shouldn't get here but just incase
this.module.removeDuelRequest(player.getUniqueId());

DuelsMessages.NO_DUEL_REQUESTS.send(player);
return;
}

DuelsMessages.DUEL_REQUEST_CANCELLED.send(player, target.getName());
DuelsMessages.CANCELLED_DUEL_REQUEST.send(target, player.getName());

this.module.removeDuelRequest(player.getUniqueId());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.battleplugins.arena.module.duels;

import org.battleplugins.arena.messages.Message;
import org.battleplugins.arena.messages.Messages;

public final class DuelsMessages {
public static final Message CANNOT_DUEL_SELF = Messages.error("duel-cannot-duel-self", "You cannot duel yourself!");
public static final Message DUEL_REQUEST_SENT = Messages.info("duel-request-sent", "Duel request sent to <secondary>{}</secondary>!");
public static final Message DUEL_REQUEST_RECEIVED = Messages.info("duel-request-received", "You have received a duel request from <secondary>{}</secondary>! Type <secondary>/{} duel accept {}</secondary> to accept or <secondary>/{} duel deny {}</secondary> to deny.");
public static final Message DUEL_REQUEST_ALREADY_SENT = Messages.error("duel-request-already-sent", "You have already have an outgoing duel request! Type <secondary>/{} duel cancel</secondary> to cancel.");
public static final Message NO_DUEL_REQUESTS = Messages.error("duel-no-requests", "You have no duel requests!");
public static final Message USER_DID_NOT_REQUEST = Messages.error("duel-user-did-not-request", "<secondary>{}</secondary> did not request a duel with you! You can only accept requests from the user who sent it.");
public static final Message DUEL_REQUEST_DENIED = Messages.info("duel-request-denied", "You have denied the duel request from <secondary>{}</secondary>!");
public static final Message DENIED_DUEL_REQUEST = Messages.error("duel-denied-request", "<secondary>{}</secondary> has denied your duel request!");
public static final Message DUEL_REQUEST_CANCELLED = Messages.info("duel-request-cancelled", "You have cancelled your duel request to <secondary>{}</secondary>!");
public static final Message CANCELLED_DUEL_REQUEST = Messages.error("duel-cancelled-request", "<secondary>{}</secondary> has cancelled their duel request!");
public static final Message DUEL_REQUESTED_CANCELLED_QUIT = Messages.info("duel-request-cancelled-quit", "Your duel request from <secondary>{}</secondary> has been cancelled as they have left the server.");
public static final Message DUEL_REQUEST_ACCEPTED = Messages.info("duel-request-accepted", "You have accepted the duel request from <secondary>{}</secondary>! The duel will commence in <secondary>5 seconds</secondary>!");
public static final Message ACCEPTED_DUEL_REQUEST = Messages.info("duel-accepted-request", "<secondary>{}</secondary> has accepted your duel request! The duel will commence in <secondary>5 seconds</secondary>!");
public static final Message PENDING_DUEL_REQUEST = Messages.error("duel-pending-request", "You have a pending outgoing duel request! Type <secondary>/arena duel cancel</secondary> to cancel.");
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
int maxArgs() default -1;

boolean overrideDisabled() default false;

boolean requiresOp() default false;

String permissionNode() default "";

String description() default "";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.battleplugins.arena.command;

import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.format.NamedTextColor;
import org.battleplugins.arena.Arena;
import org.battleplugins.arena.ArenaPlayer;
Expand Down Expand Up @@ -33,8 +32,6 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

public class ArenaCommandExecutor extends BaseCommandExecutor {
protected final Arena arena;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void postProcess() {
* @param arena the arena to create the competition for
* @return the created competition
*/
public Competition<?> createCompetition(Arena arena) {
public LiveCompetition<?> createCompetition(Arena arena) {
return new LiveCompetition<>(arena, arena.getType(), this);
}

Expand Down Expand Up @@ -224,7 +224,7 @@ public final void setSpawns(Spawns spawns) {
* @return the created dynamic competition
*/
@Nullable
public final Competition<?> createDynamicCompetition(Arena arena) {
public final LiveCompetition<?> createDynamicCompetition(Arena arena) {
if (this.type != MapType.DYNAMIC) {
throw new IllegalStateException("Cannot create dynamic competition for non-dynamic map!");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public void onChatInput(String input) {

@Override
public boolean isValidChatInput(String input) {
return !input.startsWith("/") && SpawnInputStage.this.input.equalsIgnoreCase(input);
return super.isValidChatInput(input) && !input.startsWith("/") && SpawnInputStage.this.input.equalsIgnoreCase(input);
}
}.bind(context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ public void onChatInput(String input) {

@Override
public boolean isValidChatInput(String input) {
return !input.startsWith("/") && teamNames.contains(input);
return super.isValidChatInput(input) && (!input.startsWith("/") && teamNames.contains(input));
}
}.bind(context);
}

@Override
public boolean isValidChatInput(String input) {
return input.equalsIgnoreCase("clear") || input.equalsIgnoreCase("done") || (!input.startsWith("/") && TeamSpawnInputStage.this.input.equalsIgnoreCase(input));
return super.isValidChatInput(input) && (input.equalsIgnoreCase("clear") || input.equalsIgnoreCase("done") || (!input.startsWith("/") && TeamSpawnInputStage.this.input.equalsIgnoreCase(input)));
}
}.bind(context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public void onChatInput(String input) {

@Override
public boolean isValidChatInput(String input) {
return (!input.startsWith("/") && (validContentFunction == null || validContentFunction.apply(context, input)));
return super.isValidChatInput(input) && (!input.startsWith("/") && (validContentFunction == null || validContentFunction.apply(context, input)));
}
}.bind(context);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public ChatInput(Player player, Message invalidInput) {
Listener createListener(Player player) {
return new Listener() {

@EventHandler(ignoreCancelled = true)
@EventHandler
public void onChat(AsyncChatEvent event) {
if (!player.equals(event.getPlayer())) {
return;
Expand All @@ -53,6 +53,11 @@ public void onChat(AsyncChatEvent event) {
event.setCancelled(true);
String message = PlainTextComponentSerializer.plainText().serialize(event.originalMessage());
if (!isValidChatInput(message)) {
// Don't send feedback if the message is "cancel"
if (message.equalsIgnoreCase("cancel")) {
return;
}

if (invalidInput != null) {
invalidInput.send(player);
}
Expand Down Expand Up @@ -85,7 +90,7 @@ public void onChat(AsyncChatEvent event) {
* @return true if the input is valid, false otherwise
*/
public boolean isValidChatInput(String input) {
return true;
return !input.contains("cancel");
}
}

Expand Down
Loading

0 comments on commit 582432b

Please sign in to comment.