fix(arena): move winners outside after victory

This commit is contained in:
dmg
2026-09-04 22:01:52 -04:00
parent f0dbde17b8
commit 17a5c66575
5 changed files with 85 additions and 2 deletions
@@ -400,7 +400,7 @@ public final class RoleArenaController implements Listener, Runnable {
&& !zombie.isDead() ? zombie : null;
}
private void assignRole(UUID playerId, ArenaRole role) {
void assignRole(UUID playerId, ArenaRole role) {
LifecycleState assigned;
try {
assigned = role == ArenaRole.TYRANT
@@ -414,13 +414,35 @@ public final class RoleArenaController implements Listener, Runnable {
stateManager.saveIfDirty();
challengerId = null;
barrier.clear();
String name = Optional.ofNullable(server.getPlayer(playerId))
Player winner = server.getPlayer(playerId);
moveWinnerOutside(winner);
String name = Optional.ofNullable(winner)
.map(Player::getName).orElse(playerId.toString());
String message = ChatColor.YELLOW + name + " defeated the arena boss and is the "
+ readable(role) + "!";
server.getOnlinePlayers().forEach(player -> player.sendMessage(message));
}
private void moveWinnerOutside(Player winner) {
Optional<ArenaLocation> configured = locations.location();
if (winner == null || configured.isEmpty()) {
return;
}
ArenaLocation arena = configured.orElseThrow();
Location winnerLocation = winner.getLocation();
if (!contains(arena, winnerLocation)) {
return;
}
relocating.add(winner.getUniqueId());
try {
winner.teleport(
outside(arena, winnerLocation), PlayerTeleportEvent.TeleportCause.PLUGIN
);
} finally {
relocating.remove(winner.getUniqueId());
}
}
private void announceVacancy(ArenaLocation arena, ArenaRole role) {
String message = vacancyMessage(arena, role);
for (Player player : server.getOnlinePlayers()) {
@@ -4,6 +4,9 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -16,7 +19,10 @@ import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import org.bukkit.event.player.PlayerJoinEvent;
import org.junit.jupiter.api.Test;
@@ -38,6 +44,16 @@ final class RoleArenaControllerTest {
);
}
@Test
void tyrantArenaWinnerIsMovedOutsideAfterAssignment() {
assertWinnerMovedOutside(ArenaRole.TYRANT, tyrantVacancy());
}
@Test
void vigilanteArenaWinnerIsMovedOutsideAfterAssignment() {
assertWinnerMovedOutside(ArenaRole.VIGILANTE, openGame());
}
@Test
void optedInPlayerJoiningDuringVacancyReceivesArenaCoordinates() {
Player player = mock(Player.class);
@@ -102,6 +118,43 @@ final class RoleArenaControllerTest {
verify(player, never()).sendMessage(org.mockito.ArgumentMatchers.anyString());
}
private static void assertWinnerMovedOutside(ArenaRole role, GameState game) {
ArenaLocation arena = new ArenaLocation("world", 10.0, 64.0, -5.0, 0.0F, 0.0F);
World world = mock(World.class);
when(world.getName()).thenReturn("world");
when(world.getMinHeight()).thenReturn(-64);
when(world.getMaxHeight()).thenReturn(320);
when(world.getHighestBlockYAt(org.mockito.ArgumentMatchers.anyInt(),
org.mockito.ArgumentMatchers.anyInt())).thenReturn(63);
when(world.getBlockAt(org.mockito.ArgumentMatchers.anyInt(),
org.mockito.ArgumentMatchers.anyInt(),
org.mockito.ArgumentMatchers.anyInt())).thenReturn(mock(Block.class));
Player player = mock(Player.class);
when(player.getUniqueId()).thenReturn(PLAYER);
when(player.getName()).thenReturn("Player");
when(player.getLocation()).thenReturn(new Location(world, arena.x(), arena.y(), arena.z()));
PlayerState playerState = PlayerState.newPlayer(PLAYER, "Player");
TyrantStateManager manager = mock(TyrantStateManager.class);
when(manager.snapshot()).thenReturn(new PersistentState(game, Map.of(PLAYER, playerState)));
Server server = mock(Server.class);
when(server.getPlayer(PLAYER)).thenReturn(player);
when(server.getWorld("world")).thenReturn(world);
doReturn(Set.of(player)).when(server).getOnlinePlayers();
ArenaLocationStore locations = mock(ArenaLocationStore.class);
when(locations.location()).thenReturn(Optional.of(arena));
RoleArenaController controller = new RoleArenaController(
manager, server, locations, PluginSettings.from(Map.of())
);
controller.assignRole(PLAYER, role);
verify(manager).replaceState(org.mockito.ArgumentMatchers.any(LifecycleState.class));
verify(player).teleport(argThat((Location destination) ->
!ArenaGeometry.contains(arena, 10.0, "world",
destination.getX(), destination.getY(), destination.getZ())
), eq(org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.PLUGIN));
}
private static PlayerJoinEvent mockJoin(Player player) {
PlayerJoinEvent event = mock(PlayerJoinEvent.class);
when(event.getPlayer()).thenReturn(player);