Files
Bedwars/src/main/java/com/bedwars/GameManager.java
T
Cortex Builder 16433a893f premier commit
2026-06-11 20:14:58 +02:00

1041 lines
41 KiB
Java

package com.bedwars;
import org.bukkit.*;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.FireworkMeta;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.scheduler.BukkitTask;
import org.bukkit.event.entity.EntityDamageEvent;
import java.util.*;
public class GameManager {
private final BedwarsPlugin plugin;
private GameState state = GameState.LOBBY;
private final Map<UUID, BedwarsTeam> playerTeams = new HashMap<>();
private final Map<BedwarsTeam, Boolean> teamBeds = new HashMap<>();
private final Set<UUID> spectators = new HashSet<>();
private final Set<BedwarsTeam> eliminatedTeams = new HashSet<>();
private final Set<UUID> eliminatedPlayers = new HashSet<>();
// Stats
private final Map<UUID, Integer> kills = new HashMap<>();
private final Map<UUID, Integer> bedsBroken = new HashMap<>();
// Combat Tracking
private final Map<UUID, UUID> lastAttacker = new HashMap<>();
private final Map<UUID, Long> lastAttackTime = new HashMap<>();
private final Map<UUID, LastDamageType> lastDamageType = new HashMap<>();
// Countdowns
private boolean countingDown = false;
private int countdownTime = 30;
private BukkitTask countdownTask;
private BukkitTask gameLoopTask;
private final List<BukkitTask> respawnTasks = new ArrayList<>();
private int gameTimeTicks = 0;
public GameManager(BedwarsPlugin plugin) {
this.plugin = plugin;
resetStats();
}
public void init() {
// Initialize bed status
for (BedwarsTeam team : BedwarsTeam.values()) {
teamBeds.put(team, true);
}
// Save pristine bed states from world
plugin.getArenaManager().saveBedStates();
}
public GameState getState() {
return state;
}
public void setState(GameState state) {
this.state = state;
plugin.getScoreboardManager().updateAll();
}
public boolean isCountingDown() {
return countingDown;
}
public int getCountdownTime() {
return countdownTime;
}
public BedwarsTeam getPlayerTeam(Player player) {
return playerTeams.get(player.getUniqueId());
}
public void setPlayerTeam(Player player, BedwarsTeam team) {
playerTeams.put(player.getUniqueId(), team);
updateTabName(player);
plugin.getScoreboardManager().updateAll();
}
public void updateTabName(Player player) {
player.setPlayerListHeaderFooter("", "");
BedwarsTeam team = getPlayerTeam(player);
if (team != null) {
if (isSpectator(player)) {
player.setPlayerListName("§7" + player.getName());
player.setDisplayName("§7" + player.getName() + "§r");
} else {
player.setPlayerListName(team.getColor() + player.getName());
player.setDisplayName(team.getColor() + player.getName() + "§r");
}
} else {
player.setPlayerListName("§7" + player.getName());
player.setDisplayName("§7" + player.getName() + "§r");
}
}
public boolean hasBed(BedwarsTeam team) {
return teamBeds.getOrDefault(team, false);
}
public void setBedBroken(BedwarsTeam team, boolean broken) {
teamBeds.put(team, !broken);
plugin.getScoreboardManager().updateAll();
}
public boolean isSpectator(Player player) {
return spectators.contains(player.getUniqueId());
}
public int getKills(Player player) {
return kills.getOrDefault(player.getUniqueId(), 0);
}
public void addKill(Player player) {
kills.put(player.getUniqueId(), getKills(player) + 1);
plugin.getScoreboardManager().updateScoreboard(player);
}
public int getBedsBroken(Player player) {
return bedsBroken.getOrDefault(player.getUniqueId(), 0);
}
public void addBedBroken(Player player) {
bedsBroken.put(player.getUniqueId(), getBedsBroken(player) + 1);
plugin.getScoreboardManager().updateScoreboard(player);
}
public void resetStats() {
playerTeams.clear();
spectators.clear();
eliminatedTeams.clear();
eliminatedPlayers.clear();
kills.clear();
bedsBroken.clear();
lastAttacker.clear();
lastAttackTime.clear();
lastDamageType.clear();
for (BedwarsTeam team : BedwarsTeam.values()) {
teamBeds.put(team, false); // Disabled until game starts
}
if (plugin.getUpgradesManager() != null) {
plugin.getUpgradesManager().resetTeamUpgrades();
}
if (plugin.getShopManager() != null) {
plugin.getShopManager().resetAllShopData();
}
gameTimeTicks = 0;
// Show all players to all players again
for (Player p1 : Bukkit.getOnlinePlayers()) {
for (Player p2 : Bukkit.getOnlinePlayers()) {
p1.showPlayer(plugin, p2);
}
}
}
/**
* Attempts to start the lobby countdown.
*/
public void checkStart() {
if (state != GameState.LOBBY || countingDown) return;
int minPlayers = plugin.getConfig().getInt("min-players", 2);
if (Bukkit.getOnlinePlayers().size() >= minPlayers) {
startCountdown();
}
}
private void startCountdown() {
countingDown = true;
countdownTime = plugin.getConfig().getInt("countdown-seconds", 30);
countdownTask = new BukkitRunnable() {
@Override
public void run() {
if (Bukkit.getOnlinePlayers().size() < plugin.getConfig().getInt("min-players", 2)) {
cancelCountdown();
Bukkit.broadcastMessage("§cNot enough players! Countdown cancelled.");
return;
}
if (countdownTime <= 0) {
startGame();
cancel();
return;
}
if (countdownTime == 30 || countdownTime == 15 || countdownTime == 10 || countdownTime <= 5) {
Bukkit.broadcastMessage("§eThe match will begin in §a" + countdownTime + " §eseconds!");
for (Player p : Bukkit.getOnlinePlayers()) {
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 1.0f);
}
}
countdownTime--;
plugin.getScoreboardManager().updateAll();
}
}.runTaskTimer(plugin, 0L, 20L);
}
public void cancelCountdown() {
countingDown = false;
if (countdownTask != null) {
countdownTask.cancel();
}
plugin.getScoreboardManager().updateAll();
}
/**
* Core Game Start logic.
*/
public void startGame() {
setState(GameState.PLAYING);
countingDown = false;
// Remove waiting area glass cage
plugin.getArenaManager().removeWaitingLobby();
// Purge residual mobs from world region files
plugin.getArenaManager().clearAllMobs();
// 1. Setup active teams in the game
List<BedwarsTeam> activeTeams = new ArrayList<>();
ConfigurationSection teamsSec = plugin.getConfig().getConfigurationSection("locations.teams");
if (teamsSec != null) {
for (String key : teamsSec.getKeys(false)) {
if (teamsSec.getBoolean(key + ".enabled", false)) {
try {
BedwarsTeam t = BedwarsTeam.valueOf(key.toUpperCase());
activeTeams.add(t);
teamBeds.put(t, true); // Bed active!
} catch (Exception ignored) {}
}
}
}
if (activeTeams.isEmpty()) {
Bukkit.broadcastMessage("§cError: No teams have been configured in /bw setup! Force ending game.");
endGame(null);
return;
}
// 2. Distribute players into teams
List<Player> players = new ArrayList<>(Bukkit.getOnlinePlayers());
Collections.shuffle(players);
int teamIndex = 0;
for (Player player : players) {
BedwarsTeam team = activeTeams.get(teamIndex);
setPlayerTeam(player, team);
teamIndex = (teamIndex + 1) % activeTeams.size();
// Set up player
player.setGameMode(GameMode.SURVIVAL);
player.setHealth(20.0);
player.setFoodLevel(20);
player.setSaturation(20.0f);
player.getInventory().clear();
player.getEnderChest().clear();
// Clear potion effects
for (org.bukkit.potion.PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
// Hide spectators from this player
hideAllSpectatorsFrom(player);
// Apply starting gear
giveStartingGear(player);
// Teleport to Team Spawn
teleportToTeamSpawn(player, team);
// Setup tab and display name colors
updateTabName(player);
player.sendMessage("§eMatch started! You are in team: " + team.getColorizedName());
player.playSound(player.getLocation(), Sound.ENTITY_ENDER_DRAGON_GROWL, 0.8f, 1.0f);
}
// Mark empty teams as eliminated immediately so they don't block victory
for (BedwarsTeam team : activeTeams) {
int teamSize = 0;
for (Player p : Bukkit.getOnlinePlayers()) {
if (getPlayerTeam(p) == team) {
teamSize++;
}
}
if (teamSize == 0) {
teamBeds.put(team, false);
eliminatedTeams.add(team);
}
}
// 3. Spawn Shop Keepers & Upgrades Shop Keepers
spawnNPCs(activeTeams);
// Place enderchests for active teams asynchronously to prevent synchronous chunk loading locks
String worldName = plugin.getConfig().getString("world-name", "bedwars");
World world = Bukkit.getWorld(worldName);
if (world != null) {
for (BedwarsTeam team : activeTeams) {
String teamName = team.getName().toLowerCase();
String path = "locations.teams." + teamName + ".enderchest";
if (plugin.getConfig().contains(path)) {
final double x = plugin.getConfig().getDouble(path + ".x");
final double y = plugin.getConfig().getDouble(path + ".y");
final double z = plugin.getConfig().getDouble(path + ".z");
world.getChunkAtAsync((int) x >> 4, (int) z >> 4).thenAccept(chunk -> {
chunk.getWorld().getBlockAt((int) x, (int) y, (int) z).setType(Material.ENDER_CHEST);
});
}
}
}
// 4. Load generators and start game loop task
plugin.getGeneratorManager().loadGenerators();
startGameLoop();
Bukkit.broadcastMessage("§a§lThe game has begun! Protect your bed!");
checkWinner();
}
private void giveStartingGear(Player player) {
player.getInventory().setItem(0, new ItemStack(Material.WOODEN_SWORD));
// Give leather armor colored with team dye
BedwarsTeam team = getPlayerTeam(player);
if (team != null) {
player.getInventory().setHelmet(createColoredArmor(Material.LEATHER_HELMET, team.getColor()));
player.getInventory().setChestplate(createColoredArmor(Material.LEATHER_CHESTPLATE, team.getColor()));
// Retrieve and equip permanent bought armor tier, falling back to team colored leather
int tier = plugin.getShopManager().getArmorTier(player);
if (tier > 0) {
plugin.getShopManager().equipArmorTier(player, tier);
} else {
player.getInventory().setLeggings(createColoredArmor(Material.LEATHER_LEGGINGS, team.getColor()));
player.getInventory().setBoots(createColoredArmor(Material.LEATHER_BOOTS, team.getColor()));
}
// Retrieve and give permanent tools (Shears, Pickaxe, Axe)
plugin.getShopManager().giveTools(player);
}
}
private ItemStack createColoredArmor(Material material, ChatColor chatColor) {
ItemStack item = new ItemStack(material);
org.bukkit.inventory.meta.LeatherArmorMeta meta = (org.bukkit.inventory.meta.LeatherArmorMeta) item.getItemMeta();
if (meta != null) {
Color color = Color.WHITE;
if (chatColor == ChatColor.RED) color = Color.RED;
else if (chatColor == ChatColor.BLUE) color = Color.BLUE;
else if (chatColor == ChatColor.DARK_PURPLE) color = Color.PURPLE;
else if (chatColor == ChatColor.YELLOW) color = Color.YELLOW;
meta.setColor(color);
meta.setUnbreakable(true);
item.setItemMeta(meta);
}
return item;
}
private void teleportToTeamSpawn(Player player, BedwarsTeam team) {
String colorName = team.getName().toLowerCase();
String worldName = plugin.getConfig().getString("world-name", "bedwars");
World w = Bukkit.getWorld(worldName);
if (w != null && plugin.getConfig().contains("locations.teams." + colorName + ".spawn")) {
double x = plugin.getConfig().getDouble("locations.teams." + colorName + ".spawn.x");
double y = plugin.getConfig().getDouble("locations.teams." + colorName + ".spawn.y");
double z = plugin.getConfig().getDouble("locations.teams." + colorName + ".spawn.z");
float yaw = (float) plugin.getConfig().getDouble("locations.teams." + colorName + ".spawn.yaw");
float pitch = (float) plugin.getConfig().getDouble("locations.teams." + colorName + ".spawn.pitch");
player.teleport(new Location(w, x, y, z, yaw, pitch));
} else {
// Fallback
player.teleport(w != null ? w.getSpawnLocation() : player.getWorld().getSpawnLocation());
}
}
private void spawnNPCs(List<BedwarsTeam> activeTeams) {
String worldName = plugin.getConfig().getString("world-name", "bedwars");
World world = Bukkit.getWorld(worldName);
if (world == null) return;
// Clear existing villager entities in the bedwars world
world.getEntitiesByClass(org.bukkit.entity.Villager.class).forEach(org.bukkit.entity.Entity::remove);
for (BedwarsTeam team : activeTeams) {
String path = "locations.teams." + team.getName().toLowerCase();
// 1. Spawn Item Shop Villager
if (plugin.getConfig().contains(path + ".shop")) {
double x = plugin.getConfig().getDouble(path + ".shop.x");
double y = plugin.getConfig().getDouble(path + ".shop.y");
double z = plugin.getConfig().getDouble(path + ".shop.z");
float yaw = (float) plugin.getConfig().getDouble(path + ".shop.yaw");
float pitch = (float) plugin.getConfig().getDouble(path + ".shop.pitch");
org.bukkit.entity.Villager villager = world.spawn(new Location(world, x, y, z, yaw, pitch), org.bukkit.entity.Villager.class);
villager.setCustomName("§a§lITEM SHOP\n§7Right Click");
villager.setCustomNameVisible(true);
villager.setProfession(org.bukkit.entity.Villager.Profession.ARMORER);
villager.setAI(false);
villager.setInvulnerable(true);
villager.setSilent(true);
}
// 2. Spawn Upgrades Shop Villager
if (plugin.getConfig().contains(path + ".upgrades")) {
double x = plugin.getConfig().getDouble(path + ".upgrades.x");
double y = plugin.getConfig().getDouble(path + ".upgrades.y");
double z = plugin.getConfig().getDouble(path + ".upgrades.z");
float yaw = (float) plugin.getConfig().getDouble(path + ".upgrades.yaw");
float pitch = (float) plugin.getConfig().getDouble(path + ".upgrades.pitch");
org.bukkit.entity.Villager villager = world.spawn(new Location(world, x, y, z, yaw, pitch), org.bukkit.entity.Villager.class);
villager.setCustomName("§b§lTEAM UPGRADES\n§7Right Click");
villager.setCustomNameVisible(true);
villager.setProfession(org.bukkit.entity.Villager.Profession.WEAPONSMITH);
villager.setAI(false);
villager.setInvulnerable(true);
villager.setSilent(true);
}
}
}
private void startGameLoop() {
gameTimeTicks = 0;
gameLoopTask = new BukkitRunnable() {
@Override
public void run() {
if (state != GameState.PLAYING) {
cancel();
return;
}
// Tick generators
plugin.getGeneratorManager().tick();
// Increment ticks and check game duration (20 minutes = 24000 ticks)
gameTimeTicks++;
// Custom regeneration every 5 seconds (100 ticks)
if (gameTimeTicks % 100 == 0) {
for (Player player : Bukkit.getOnlinePlayers()) {
if (!isSpectator(player) && !eliminatedPlayers.contains(player.getUniqueId())) {
if (!player.isDead() && player.getHealth() > 0) {
double maxHealth = player.getMaxHealth();
double currentHealth = player.getHealth();
if (currentHealth < maxHealth) {
player.setHealth(Math.min(maxHealth, currentHealth + 1.0));
}
}
}
}
}
int secondsLeft = (24000 - gameTimeTicks) / 20;
if (gameTimeTicks < 24000 && gameTimeTicks % 20 == 0) {
// This runs once every second
if (secondsLeft == 300) { // 5 minutes
Bukkit.broadcastMessage("§c§lWARNING! §eThe game will end in §a5 minutes§e!");
} else if (secondsLeft == 60) { // 1 minute
Bukkit.broadcastMessage("§c§lWARNING! §eThe game will end in §a1 minute§e!");
} else if (secondsLeft == 30) {
Bukkit.broadcastMessage("§c§lWARNING! §eThe game will end in §a30 seconds§e!");
} else if (secondsLeft == 10) {
Bukkit.broadcastMessage("§c§lWARNING! §eThe game will end in §a10 seconds§e!");
} else if (secondsLeft > 0 && secondsLeft <= 5) {
Bukkit.broadcastMessage("§c§lWARNING! §eThe game will end in §c" + secondsLeft + " §eseconds!");
for (Player p : Bukkit.getOnlinePlayers()) {
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 1.0f);
}
}
}
if (gameTimeTicks >= 24000) {
Bukkit.broadcastMessage("§c§lTIME UP! §eThe game has ended in a draw.");
endGame(null);
cancel();
}
}
}.runTaskTimer(plugin, 0L, 1L);
}
/**
* Handles a player's death, respawn loop, or final elimination.
*/
public void handlePlayerDeath(Player player, Player killer) {
BedwarsTeam team = getPlayerTeam(player);
if (team == null) return;
// Check if player died in the void
boolean inVoid = player.getLocation().getY() <= -20.0 || (player.getLastDamageCause() != null && player.getLastDamageCause().getCause() == EntityDamageEvent.DamageCause.VOID);
// Handle tool levels and shears on death
plugin.getShopManager().handlePlayerDeath(player);
// Drop player resources or transfer to killer if in void
if (inVoid && killer != null) {
giveResourcesToKiller(player, killer);
} else {
dropPlayerResources(player);
}
// Determine death message
String deathMsg = getDeathMessage(player, killer, inVoid);
boolean isFinal = !hasBed(team);
String finalSuffix = isFinal ? " §c§lFINAL KILL!" : "";
Bukkit.broadcastMessage("§7" + deathMsg + finalSuffix);
// Clear combat tracking
clearCombatTag(player);
// Record stats
if (killer != null) {
addKill(killer);
killer.sendMessage("§eYou killed " + team.getColor() + player.getName() + "!");
killer.playSound(killer.getLocation(), Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.8f, 1.4f);
}
// Check if player has bed
if (hasBed(team)) {
// Can respawn!
startRespawnSequence(player, team);
} else {
// Eliminated!
eliminatePlayer(player);
checkWinner();
}
}
public void handlePlayerQuit(Player player) {
if (state != GameState.PLAYING) return;
if (isSpectator(player) || eliminatedPlayers.contains(player.getUniqueId())) return;
BedwarsTeam team = getPlayerTeam(player);
if (team == null) return;
// Eliminate player
eliminatedPlayers.add(player.getUniqueId());
spectators.add(player.getUniqueId());
// Broadcast quit final kill/elimination
Bukkit.broadcastMessage(team.getColor() + player.getName() + " §c§lquit and was eliminated!");
// Drop player resources at their last location
dropPlayerResources(player);
// Check if team is eliminated and check winner
checkWinner();
}
public String getFormattedName(Player player) {
BedwarsTeam team = getPlayerTeam(player);
if (team != null) {
return team.getColor() + player.getName() + "§7";
}
return "§7" + player.getName();
}
private String getDeathMessage(Player player, Player killer, boolean inVoid) {
String victimName = getFormattedName(player);
if (killer != null) {
String killerName = getFormattedName(killer);
LastDamageType type = lastDamageType.getOrDefault(player.getUniqueId(), LastDamageType.OTHER);
if (inVoid) {
switch (type) {
case FIREBALL:
return victimName + " was fireballed into the void by " + killerName + ".";
case TNT:
return victimName + " was blown into the void by " + killerName + ".";
case PROJECTILE:
return victimName + " was shot into the void by " + killerName + ".";
case MELEE:
default:
return victimName + " was knocked into the void by " + killerName + ".";
}
} else {
switch (type) {
case FIREBALL:
return victimName + " was fireballed by " + killerName + ".";
case TNT:
return victimName + " was blown up by " + killerName + ".";
case PROJECTILE:
return victimName + " was shot by " + killerName + ".";
case MELEE:
default:
return victimName + " was slain by " + killerName + ".";
}
}
} else {
if (inVoid) {
return victimName + " fell into the void.";
} else {
EntityDamageEvent lastDamage = player.getLastDamageCause();
if (lastDamage != null) {
EntityDamageEvent.DamageCause cause = lastDamage.getCause();
if (cause == EntityDamageEvent.DamageCause.FALL) {
return victimName + " fell to their death.";
} else if (cause == EntityDamageEvent.DamageCause.BLOCK_EXPLOSION || cause == EntityDamageEvent.DamageCause.ENTITY_EXPLOSION) {
return victimName + " was blown up.";
}
}
return victimName + " died.";
}
}
}
private void dropPlayerResources(Player player) {
Location loc = player.getLocation();
for (ItemStack item : player.getInventory().getContents()) {
if (item != null) {
Material type = item.getType();
if (type == Material.IRON_INGOT || type == Material.GOLD_INGOT ||
type == Material.DIAMOND || type == Material.EMERALD) {
loc.getWorld().dropItemNaturally(loc, item.clone());
}
}
}
player.getInventory().clear();
}
private void giveResourcesToKiller(Player player, Player killer) {
for (ItemStack item : player.getInventory().getContents()) {
if (item != null) {
Material type = item.getType();
if (type == Material.IRON_INGOT || type == Material.GOLD_INGOT ||
type == Material.DIAMOND || type == Material.EMERALD) {
// Give directly to killer's inventory
HashMap<Integer, ItemStack> remaining = killer.getInventory().addItem(item.clone());
if (!remaining.isEmpty()) {
// Drop any items that don't fit at killer's feet
for (ItemStack overflow : remaining.values()) {
killer.getWorld().dropItemNaturally(killer.getLocation(), overflow);
}
}
// Send informative message to killer
killer.sendMessage("§aReceived " + item.getAmount() + "x " + formatMaterialName(type) + " §afrom " + player.getName() + "'s void death!");
}
}
}
player.getInventory().clear();
}
private String formatMaterialName(Material material) {
switch (material) {
case IRON_INGOT:
return "§fIron";
case GOLD_INGOT:
return "§eGold";
case DIAMOND:
return "§bDiamond";
case EMERALD:
return "§aEmerald";
default:
return material.name();
}
}
public void setLastAttacker(Player victim, Player attacker, LastDamageType type) {
lastAttacker.put(victim.getUniqueId(), attacker.getUniqueId());
lastAttackTime.put(victim.getUniqueId(), System.currentTimeMillis());
lastDamageType.put(victim.getUniqueId(), type);
}
public Player getLastAttacker(Player player) {
UUID victimId = player.getUniqueId();
if (lastAttacker.containsKey(victimId)) {
long time = lastAttackTime.getOrDefault(victimId, 0L);
if (System.currentTimeMillis() - time <= 15000) { // 15 seconds combat window
UUID attackerId = lastAttacker.get(victimId);
return Bukkit.getPlayer(attackerId);
}
}
return null;
}
public void clearCombatTag(Player player) {
lastAttacker.remove(player.getUniqueId());
lastAttackTime.remove(player.getUniqueId());
lastDamageType.remove(player.getUniqueId());
}
private void startRespawnSequence(Player player, BedwarsTeam team) {
spectators.add(player.getUniqueId());
player.setGameMode(GameMode.SPECTATOR);
player.teleport(player.getLocation().clone().add(0, 5, 0));
updateTabName(player);
BukkitTask task = new BukkitRunnable() {
int time = 5;
@Override
public void run() {
if (state != GameState.PLAYING || !player.isOnline()) {
cancel();
return;
}
if (time <= 0) {
respawnPlayer(player, team);
cancel();
return;
}
player.sendTitle("§cYOU DIED!", "§eRespawning in §a" + time + "s", 0, 22, 0);
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.8f, 1.2f);
time--;
}
}.runTaskTimer(plugin, 0L, 20L);
respawnTasks.add(task);
}
private void respawnPlayer(Player player, BedwarsTeam team) {
spectators.remove(player.getUniqueId());
player.setGameMode(GameMode.SURVIVAL);
player.setHealth(20.0);
player.setFoodLevel(20);
player.setSaturation(20.0f);
player.getInventory().clear();
// Clear potion effects
for (org.bukkit.potion.PotionEffect effect : player.getActivePotionEffects()) {
player.removePotionEffect(effect.getType());
}
// Hide all active spectators from this player
hideAllSpectatorsFrom(player);
// Gear
giveStartingGear(player);
// Apply passive team upgrades (Haste, Sharpness, Protection)
plugin.getUpgradesManager().applyTeamUpgrades(player);
teleportToTeamSpawn(player, team);
updateTabName(player);
player.sendTitle("§a§lRESPAWNED!", "§fGo get them!", 5, 20, 5);
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 0.8f, 1.5f);
}
private void eliminatePlayer(Player player) {
spectators.add(player.getUniqueId());
eliminatedPlayers.add(player.getUniqueId());
player.setGameMode(GameMode.CREATIVE);
player.getInventory().clear();
giveSpectatorItems(player);
hideSpectator(player);
updateTabName(player);
player.sendTitle("§c§lELIMINATED!", "§7You have no respawns left!", 10, 40, 10);
player.playSound(player.getLocation(), Sound.ENTITY_LIGHTNING_BOLT_THUNDER, 0.8f, 0.8f);
}
public void addSpectator(Player player) {
spectators.add(player.getUniqueId());
player.setGameMode(GameMode.CREATIVE);
player.getInventory().clear();
giveSpectatorItems(player);
hideSpectator(player);
updateTabName(player);
plugin.getScoreboardManager().updateAll();
}
public void giveSpectatorItems(Player player) {
player.getInventory().clear();
ItemStack compass = new ItemStack(Material.COMPASS);
org.bukkit.inventory.meta.ItemMeta m1 = compass.getItemMeta();
if (m1 != null) {
m1.setDisplayName("§a§lTeleporter §7(Right Click)");
compass.setItemMeta(m1);
}
player.getInventory().setItem(0, compass);
ItemStack bed = new ItemStack(Material.RED_BED);
org.bukkit.inventory.meta.ItemMeta m2 = bed.getItemMeta();
if (m2 != null) {
m2.setDisplayName("§c§lReturn to Lobby §7(Right Click)");
bed.setItemMeta(m2);
}
player.getInventory().setItem(8, bed);
}
public void hideSpectator(Player player) {
for (Player p : Bukkit.getOnlinePlayers()) {
if (!isSpectator(p)) {
p.hidePlayer(plugin, player);
}
}
}
public void hideAllSpectatorsFrom(Player alivePlayer) {
for (UUID specId : spectators) {
Player spec = Bukkit.getPlayer(specId);
if (spec != null && spec.isOnline()) {
alivePlayer.hidePlayer(plugin, spec);
}
}
}
public boolean isTeamEnabled(BedwarsTeam team) {
return plugin.getConfig().getBoolean("locations.teams." + team.getName().toLowerCase() + ".enabled", false);
}
public int getAliveTeamCount(BedwarsTeam team) {
int alive = 0;
for (Player p : Bukkit.getOnlinePlayers()) {
if (getPlayerTeam(p) == team && !eliminatedPlayers.contains(p.getUniqueId())) {
alive++;
}
}
return alive;
}
/**
* Checks if only one team is left alive.
*/
public void checkWinner() {
if (state != GameState.PLAYING) return;
List<BedwarsTeam> activeTeams = new ArrayList<>();
ConfigurationSection teamsSec = plugin.getConfig().getConfigurationSection("locations.teams");
if (teamsSec != null) {
for (String key : teamsSec.getKeys(false)) {
if (teamsSec.getBoolean(key + ".enabled", false)) {
activeTeams.add(BedwarsTeam.valueOf(key.toUpperCase()));
}
}
}
// Check for team eliminations (if getAliveTeamCount(team) == 0, even if there is a bed, the team is eliminated!)
for (BedwarsTeam team : activeTeams) {
if (!eliminatedTeams.contains(team)) {
if (getAliveTeamCount(team) == 0) {
eliminatedTeams.add(team);
teamBeds.put(team, false); // No bed active if team has no alive players!
Bukkit.broadcastMessage("§r");
Bukkit.broadcastMessage("§d§lTEAM ELIMINATED! §fTeam " + team.getColor() + team.name() + " §fhas been §c§lELIMINATED§f!");
Bukkit.broadcastMessage("§r");
}
}
}
BedwarsTeam winningTeam = null;
int activeTeamCount = 0;
for (BedwarsTeam team : activeTeams) {
// A team is active if they have at least one alive player
if (getAliveTeamCount(team) > 0) {
activeTeamCount++;
winningTeam = team;
}
}
// If there is only one player online, do not end the game so they can test features alone!
if (Bukkit.getOnlinePlayers().size() > 1) {
if (activeTeamCount <= 1) {
endGame(winningTeam);
}
}
}
private BedwarsTeam winnerTeam = null;
public BedwarsTeam getWinnerTeam() {
return winnerTeam;
}
/**
* Game Over, show winner, celebrate, redirect to proxy lobby server, reset world.
*/
public void endGame(BedwarsTeam winner) {
setState(GameState.ENDING);
this.winnerTeam = winner;
if (winner != null) {
Bukkit.broadcastMessage(" §b§lVICTORY!");
Bukkit.broadcastMessage(" " + winner.getColorizedName() + " §fhas won the match!");
for (Player p : Bukkit.getOnlinePlayers()) {
p.sendTitle("§6§lVICTORY!", winner.getColorizedName() + " §fhas won!", 10, 80, 10);
p.playSound(p.getLocation(), Sound.UI_TOAST_CHALLENGE_COMPLETE, 0.8f, 1.0f);
}
// Spawn fireworks
String colorName = winner.getName().toLowerCase();
String worldName = plugin.getConfig().getString("world-name", "bedwars");
World w = Bukkit.getWorld(worldName);
if (w != null && plugin.getConfig().contains("locations.teams." + colorName + ".spawn")) {
double x = plugin.getConfig().getDouble("locations.teams." + colorName + ".spawn.x");
double y = plugin.getConfig().getDouble("locations.teams." + colorName + ".spawn.y");
double z = plugin.getConfig().getDouble("locations.teams." + colorName + ".spawn.z");
Location spawnLoc = new Location(w, x, y + 2, z);
new BukkitRunnable() {
int fireworkCount = 10;
@Override
public void run() {
if (fireworkCount <= 0 || state != GameState.ENDING) {
cancel();
return;
}
Firework fw = spawnLoc.getWorld().spawn(spawnLoc.clone().add(Math.random()*4-2, 0, Math.random()*4-2), Firework.class);
FireworkMeta meta = fw.getFireworkMeta();
meta.addEffect(FireworkEffect.builder()
.withColor(winner.getColor() == ChatColor.RED ? Color.RED : winner.getColor() == ChatColor.BLUE ? Color.BLUE : winner.getColor() == ChatColor.DARK_PURPLE ? Color.PURPLE : Color.YELLOW)
.with(FireworkEffect.Type.BALL_LARGE)
.flicker(true)
.trail(true)
.build());
meta.setPower(1);
fw.setFireworkMeta(meta);
fireworkCount--;
}
}.runTaskTimer(plugin, 0L, 10L);
}
} else {
Bukkit.broadcastMessage("§cThe game ended in a draw!");
}
// Start 10 seconds ending countdown before unloading and resetting world
new BukkitRunnable() {
int timeLeft = 10;
@Override
public void run() {
if (timeLeft <= 0) {
// Kick all players to trigger proxy redirection
for (Player p : Bukkit.getOnlinePlayers()) {
p.kickPlayer("§a§lGAME OVER!\n\n§fThe game has ended.\n§eWinner: " + (winner != null ? winner.getColorizedName() : "§cDraw") + "\n\n§bThank you for playing!");
}
// Schedule world reset shortly after kicking so connection is fully released
Bukkit.getScheduler().runTaskLater(plugin, () -> {
// Cleanup generators and NPCs
plugin.getGeneratorManager().cleanup();
// Reset the world map
plugin.getArenaManager().resetWorld();
// Cancel all tasks
for (BukkitTask task : respawnTasks) {
task.cancel();
}
respawnTasks.clear();
if (gameLoopTask != null) {
gameLoopTask.cancel();
}
// Reinitialize variables
resetStats();
winnerTeam = null;
eliminatedTeams.clear();
setState(GameState.LOBBY);
// Check if players are already inside waiting lobby (in case they joined during reset)
checkStart();
}, 40L);
cancel();
return;
}
if (timeLeft <= 5) {
Bukkit.broadcastMessage("§eGame closing and resetting in §a" + timeLeft + " §eseconds...");
for (Player p : Bukkit.getOnlinePlayers()) {
p.playSound(p.getLocation(), Sound.BLOCK_NOTE_BLOCK_PLING, 1.0f, 1.2f);
}
}
timeLeft--;
}
}.runTaskTimer(plugin, 0L, 20L);
}
/**
* Sends players back to the configured lobby proxy server.
*/
public void sendToLobby(Player player) {
String serverName = plugin.getConfig().getString("lobby-server", "lobby");
player.sendMessage("§b§lNEXORIA §fsending you back to the lobby...");
try {
// 1. Send standard BungeeCord packets
com.google.common.io.ByteArrayDataOutput bungeeOut = com.google.common.io.ByteStreams.newDataOutput();
bungeeOut.writeUTF("Connect");
bungeeOut.writeUTF(serverName);
player.sendPluginMessage(plugin, "BungeeCord", bungeeOut.toByteArray());
player.sendPluginMessage(plugin, "bungeecord:main", bungeeOut.toByteArray());
// 2. Send custom nexoria direct channel packet
com.google.common.io.ByteArrayDataOutput nexoriaOut = com.google.common.io.ByteStreams.newDataOutput();
nexoriaOut.writeUTF("Connect");
nexoriaOut.writeUTF(player.getName());
nexoriaOut.writeUTF(serverName);
player.sendPluginMessage(plugin, "nexoria:main", nexoriaOut.toByteArray());
} catch (Exception e) {
player.sendMessage("§cFailed to redirect to proxy lobby: " + e.getMessage());
}
}
public void resetGameImmediately() {
// Cleanup generators and NPCs
plugin.getGeneratorManager().cleanup();
// Reset the world map
plugin.getArenaManager().resetWorld();
// Cancel all tasks
for (BukkitTask task : respawnTasks) {
task.cancel();
}
respawnTasks.clear();
if (gameLoopTask != null) {
gameLoopTask.cancel();
}
// Reinitialize variables
resetStats();
winnerTeam = null;
eliminatedTeams.clear();
setState(GameState.LOBBY);
countingDown = false;
if (countdownTask != null) {
countdownTask.cancel();
}
}
}