premier commit
This commit is contained in:
@@ -0,0 +1,381 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class ArenaManager {
|
||||
|
||||
private final BedwarsPlugin plugin;
|
||||
private final Set<Location> playerPlacedBlocks = new HashSet<>();
|
||||
private final java.util.Map<Location, org.bukkit.block.data.BlockData> savedBedStates = new java.util.HashMap<>();
|
||||
|
||||
public ArenaManager(BedwarsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
private File getTemplateFolder(String worldName) {
|
||||
if (worldName.equalsIgnoreCase("world")) {
|
||||
return new File(Bukkit.getWorldContainer(), "bedwars");
|
||||
} else {
|
||||
File customTemplate = new File(Bukkit.getWorldContainer(), worldName + "_template");
|
||||
if (customTemplate.exists()) {
|
||||
return customTemplate;
|
||||
}
|
||||
File bedwarsFolder = new File(Bukkit.getWorldContainer(), "bedwars");
|
||||
if (bedwarsFolder.exists()) {
|
||||
return bedwarsFolder;
|
||||
}
|
||||
File fallbackTemplate = new File(Bukkit.getWorldContainer(), "bedwars_template");
|
||||
if (fallbackTemplate.exists()) {
|
||||
return fallbackTemplate;
|
||||
}
|
||||
return new File(Bukkit.getWorldContainer(), "bedwars");
|
||||
}
|
||||
}
|
||||
|
||||
private File getWorldFolder(String worldName) {
|
||||
return new File(Bukkit.getWorldContainer(), worldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Startup file copying logic (called in plugin onLoad() before Bukkit loads worlds).
|
||||
* Automatically copies bedwars template directory to active world folder.
|
||||
*/
|
||||
public void onLoadCopy() {
|
||||
// Manually load config.yml to get world-name early on Bukkit onLoad()
|
||||
File configFile = new File(plugin.getDataFolder(), "config.yml");
|
||||
String worldName = "world";
|
||||
if (configFile.exists()) {
|
||||
org.bukkit.configuration.file.YamlConfiguration config = org.bukkit.configuration.file.YamlConfiguration.loadConfiguration(configFile);
|
||||
worldName = config.getString("world-name", "world");
|
||||
} else {
|
||||
worldName = plugin.getConfig().getString("world-name", "world");
|
||||
}
|
||||
|
||||
File templateFolder = getTemplateFolder(worldName);
|
||||
File worldFolder = getWorldFolder(worldName);
|
||||
|
||||
if (templateFolder.equals(worldFolder)) return;
|
||||
|
||||
if (templateFolder.exists()) {
|
||||
Bukkit.getLogger().info("[Bedwars] onLoad: Overwriting world '" + worldName + "' from template '" + templateFolder.getName() + "'...");
|
||||
deleteDirectory(worldFolder);
|
||||
try {
|
||||
copyDirectory(templateFolder, worldFolder);
|
||||
Bukkit.getLogger().info("[Bedwars] onLoad: Successfully copied '" + templateFolder.getName() + "' template to '" + worldName + "'!");
|
||||
} catch (IOException e) {
|
||||
Bukkit.getLogger().severe("[Bedwars] onLoad: Failed to copy template: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
// First time start: if world exists but template doesn't, initialize template!
|
||||
if (worldFolder.exists()) {
|
||||
Bukkit.getLogger().info("[Bedwars] onLoad: Template '" + templateFolder.getName() + "' not found. Creating backup of '" + worldName + "' as template '" + templateFolder.getName() + "'...");
|
||||
try {
|
||||
copyDirectory(worldFolder, templateFolder);
|
||||
Bukkit.getLogger().info("[Bedwars] onLoad: Successfully initialized template '" + templateFolder.getName() + "'!");
|
||||
} catch (IOException e) {
|
||||
Bukkit.getLogger().severe("[Bedwars] onLoad: Failed to create template: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the active game world back to the bedwars template directory (called on /bw save).
|
||||
*/
|
||||
public void setupTemplate() {
|
||||
String worldName = plugin.getConfig().getString("world-name", "world");
|
||||
File worldFolder = getWorldFolder(worldName);
|
||||
File templateFolder = getTemplateFolder(worldName);
|
||||
|
||||
plugin.getLogger().info("Saving active world '" + worldName + "' to template '" + templateFolder.getName() + "'...");
|
||||
|
||||
// Save the active world first to ensure blocks are saved to disk
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world != null) {
|
||||
world.save();
|
||||
}
|
||||
|
||||
try {
|
||||
// Overwrite template folder
|
||||
deleteDirectory(templateFolder);
|
||||
copyDirectory(worldFolder, templateFolder);
|
||||
plugin.getLogger().info("Successfully updated '" + templateFolder.getName() + "' template with setup changes!");
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().severe("Failed to save changes to template: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void saveBedStates() {
|
||||
savedBedStates.clear();
|
||||
String worldName = plugin.getConfig().getString("world-name", "world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) return;
|
||||
|
||||
for (BedwarsTeam team : BedwarsTeam.values()) {
|
||||
String path = "locations.teams." + team.getName().toLowerCase() + ".bed";
|
||||
if (plugin.getConfig().contains(path)) {
|
||||
double x = plugin.getConfig().getDouble(path + ".x");
|
||||
double y = plugin.getConfig().getDouble(path + ".y");
|
||||
double z = plugin.getConfig().getDouble(path + ".z");
|
||||
Location loc = new Location(world, x, y, z);
|
||||
|
||||
// Save this block and its surrounding blocks if they are beds
|
||||
saveBedBlock(loc.getBlock());
|
||||
saveBedBlock(loc.clone().add(1, 0, 0).getBlock());
|
||||
saveBedBlock(loc.clone().add(-1, 0, 0).getBlock());
|
||||
saveBedBlock(loc.clone().add(0, 0, 1).getBlock());
|
||||
saveBedBlock(loc.clone().add(0, 0, -1).getBlock());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveBedBlock(Block block) {
|
||||
if (block.getType().name().contains("_BED")) {
|
||||
savedBedStates.put(block.getLocation(), block.getBlockData().clone());
|
||||
}
|
||||
}
|
||||
|
||||
public void rollbackBlocks() {
|
||||
String worldName = plugin.getConfig().getString("world-name", "world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
plugin.getLogger().warning("Could not execute rollbackBlocks: World '" + worldName + "' is not loaded.");
|
||||
playerPlacedBlocks.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// 1. Clear player-placed blocks
|
||||
plugin.getLogger().info("Clearing " + playerPlacedBlocks.size() + " player-placed blocks...");
|
||||
for (Location loc : playerPlacedBlocks) {
|
||||
loc.setWorld(world);
|
||||
loc.getBlock().setType(org.bukkit.Material.AIR);
|
||||
}
|
||||
playerPlacedBlocks.clear();
|
||||
|
||||
// 2. Restore bed states
|
||||
plugin.getLogger().info("Restoring " + savedBedStates.size() + " bed blocks...");
|
||||
for (java.util.Map.Entry<Location, org.bukkit.block.data.BlockData> entry : savedBedStates.entrySet()) {
|
||||
Location loc = entry.getKey();
|
||||
loc.setWorld(world);
|
||||
Block block = loc.getBlock();
|
||||
block.setBlockData(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the game world back to the original bedwars template.
|
||||
*/
|
||||
public void resetWorld() {
|
||||
String worldName = plugin.getConfig().getString("world-name", "world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
|
||||
plugin.getLogger().info("Resetting world '" + worldName + "' from template '" + getTemplateFolder(worldName).getName() + "'...");
|
||||
|
||||
// Always execute in-memory rollback as primary/reliable mechanism!
|
||||
rollbackBlocks();
|
||||
|
||||
// 1. Kick players to lobby proxy server
|
||||
boolean unloaded = false;
|
||||
if (world != null) {
|
||||
for (Player player : world.getPlayers()) {
|
||||
plugin.getGameManager().sendToLobby(player);
|
||||
}
|
||||
// Unload the world (only works for non-default worlds once players leave)
|
||||
unloaded = Bukkit.unloadWorld(world, false);
|
||||
}
|
||||
|
||||
if (unloaded) {
|
||||
// 2. Overwrite the world folder from bedwars template
|
||||
File worldFolder = getWorldFolder(worldName);
|
||||
File templateFolder = getTemplateFolder(worldName);
|
||||
|
||||
if (templateFolder.exists()) {
|
||||
deleteDirectory(worldFolder);
|
||||
try {
|
||||
copyDirectory(templateFolder, worldFolder);
|
||||
plugin.getLogger().info("Successfully restored world '" + worldName + "' from template '" + templateFolder.getName() + "'!");
|
||||
} catch (IOException e) {
|
||||
plugin.getLogger().severe("Failed to copy bedwars template: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
plugin.getLogger().warning("Template folder '" + templateFolder.getName() + "' not found! Cannot reset world.");
|
||||
}
|
||||
|
||||
// 3. Reload the world
|
||||
World w = Bukkit.createWorld(new WorldCreator(worldName));
|
||||
if (w != null) {
|
||||
w.setGameRule(org.bukkit.GameRule.ANNOUNCE_ADVANCEMENTS, false);
|
||||
}
|
||||
plugin.getLogger().info("World '" + worldName + "' loaded and ready!");
|
||||
} else {
|
||||
plugin.getLogger().info("World '" + worldName + "' remained loaded. In-memory programmatic block rollback completed successfully!");
|
||||
}
|
||||
|
||||
// 4. Regenerate waiting area lobby glass cage
|
||||
createWaitingLobby();
|
||||
}
|
||||
|
||||
public void clearAllMobs() {
|
||||
String worldName = plugin.getConfig().getString("world-name", "world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world != null) {
|
||||
int count = 0;
|
||||
for (org.bukkit.entity.Entity entity : world.getEntities()) {
|
||||
if (entity instanceof org.bukkit.entity.Mob || entity instanceof org.bukkit.entity.Ambient) {
|
||||
if (entity.getType() == org.bukkit.entity.EntityType.VILLAGER) {
|
||||
continue;
|
||||
}
|
||||
entity.remove();
|
||||
count++;
|
||||
}
|
||||
}
|
||||
plugin.getLogger().info("Purged " + count + " pre-existing mobs from world '" + worldName + "'!");
|
||||
}
|
||||
}
|
||||
|
||||
private final Set<Location> waitingLobbyBlocks = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Spawns a floating glass cage around the waiting lobby spawnpoint.
|
||||
*/
|
||||
public void createWaitingLobby() {
|
||||
waitingLobbyBlocks.clear();
|
||||
clearAllMobs();
|
||||
|
||||
String worldName = plugin.getConfig().getString("locations.lobby.world", "world");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) return;
|
||||
|
||||
double lx = plugin.getConfig().getDouble("locations.lobby.x", 129.5);
|
||||
double ly = plugin.getConfig().getDouble("locations.lobby.y", 90.0);
|
||||
double lz = plugin.getConfig().getDouble("locations.lobby.z", 149.5);
|
||||
Location center = new Location(world, lx, ly, lz);
|
||||
|
||||
int cx = center.getBlockX();
|
||||
int cy = center.getBlockY();
|
||||
int cz = center.getBlockZ();
|
||||
|
||||
plugin.getLogger().info("Generating waiting lobby cage at: " + center);
|
||||
|
||||
// Generate 7x7 platform at floor (cy - 1) and ceiling (cy + 3)
|
||||
for (int x = cx - 3; x <= cx + 3; x++) {
|
||||
for (int z = cz - 3; z <= cz + 3; z++) {
|
||||
// Floor
|
||||
Block floor = world.getBlockAt(x, cy - 1, z);
|
||||
floor.setType(org.bukkit.Material.GLASS);
|
||||
waitingLobbyBlocks.add(floor.getLocation());
|
||||
|
||||
// Ceiling
|
||||
Block ceiling = world.getBlockAt(x, cy + 3, z);
|
||||
ceiling.setType(org.bukkit.Material.GLASS);
|
||||
waitingLobbyBlocks.add(ceiling.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
// Walls
|
||||
for (int y = cy; y < cy + 3; y++) {
|
||||
for (int x = cx - 3; x <= cx + 3; x++) {
|
||||
Block b1 = world.getBlockAt(x, y, cz - 3);
|
||||
Block b2 = world.getBlockAt(x, y, cz + 3);
|
||||
b1.setType(org.bukkit.Material.GLASS);
|
||||
b2.setType(org.bukkit.Material.GLASS);
|
||||
waitingLobbyBlocks.add(b1.getLocation());
|
||||
waitingLobbyBlocks.add(b2.getLocation());
|
||||
}
|
||||
for (int z = cz - 3; z <= cz + 3; z++) {
|
||||
Block b1 = world.getBlockAt(cx - 3, y, z);
|
||||
Block b2 = world.getBlockAt(cx + 3, y, z);
|
||||
b1.setType(org.bukkit.Material.GLASS);
|
||||
b2.setType(org.bukkit.Material.GLASS);
|
||||
waitingLobbyBlocks.add(b1.getLocation());
|
||||
waitingLobbyBlocks.add(b2.getLocation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wipes the glass waiting lobby platform when the game starts.
|
||||
*/
|
||||
public void removeWaitingLobby() {
|
||||
if (waitingLobbyBlocks.isEmpty()) return;
|
||||
|
||||
plugin.getLogger().info("Removing waiting lobby cage block by block...");
|
||||
for (Location loc : waitingLobbyBlocks) {
|
||||
loc.getBlock().setType(org.bukkit.Material.AIR);
|
||||
}
|
||||
waitingLobbyBlocks.clear();
|
||||
}
|
||||
|
||||
public void trackBlockPlace(Block block) {
|
||||
playerPlacedBlocks.add(block.getLocation());
|
||||
}
|
||||
|
||||
public boolean isPlayerPlacedBlock(Block block) {
|
||||
return playerPlacedBlocks.contains(block.getLocation());
|
||||
}
|
||||
|
||||
public void removeTrackedBlock(Block block) {
|
||||
playerPlacedBlocks.remove(block.getLocation());
|
||||
}
|
||||
|
||||
// Helper method to delete a directory recursively
|
||||
private void deleteDirectory(File path) {
|
||||
if (path.exists()) {
|
||||
File[] files = path.listFiles();
|
||||
if (files != null) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
deleteDirectory(file);
|
||||
} else {
|
||||
// Skip session.lock or uid.dat if JVM locks them
|
||||
if (file.getName().equalsIgnoreCase("session.lock") || file.getName().equalsIgnoreCase("uid.dat")) {
|
||||
continue;
|
||||
}
|
||||
file.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
path.delete();
|
||||
}
|
||||
}
|
||||
|
||||
// Helper method to copy a directory recursively
|
||||
private void copyDirectory(File source, File destination) throws IOException {
|
||||
if (source.isDirectory()) {
|
||||
if (!destination.exists()) {
|
||||
destination.mkdirs();
|
||||
}
|
||||
|
||||
String[] files = source.list();
|
||||
if (files != null) {
|
||||
for (String file : files) {
|
||||
if (file.equalsIgnoreCase("session.lock") || file.equalsIgnoreCase("uid.dat")) {
|
||||
continue; // Skip active lock files
|
||||
}
|
||||
File srcFile = new File(source, file);
|
||||
File destFile = new File(destination, file);
|
||||
copyDirectory(srcFile, destFile);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
try (InputStream in = new FileInputStream(source);
|
||||
OutputStream out = new FileOutputStream(destination)) {
|
||||
byte[] buffer = new byte[1024];
|
||||
int length;
|
||||
while ((length = in.read(buffer)) > 0) {
|
||||
out.write(buffer, 0, length);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.TabCompleter;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class BedwarsCommand implements CommandExecutor, TabCompleter {
|
||||
|
||||
private final BedwarsPlugin plugin;
|
||||
|
||||
public BedwarsCommand(BedwarsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
|
||||
if (!(sender instanceof Player player)) {
|
||||
sender.sendMessage("§cOnly players can execute setup commands!");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!player.hasPermission("bedwars.admin")) {
|
||||
player.sendMessage("§cYou do not have permission to configure Bedwars!");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (args.length == 0 || args[0].equalsIgnoreCase("help")) {
|
||||
sendHelp(player);
|
||||
return true;
|
||||
}
|
||||
|
||||
String sub = args[0].toLowerCase();
|
||||
Location loc = player.getLocation();
|
||||
|
||||
switch (sub) {
|
||||
case "setlobby" -> {
|
||||
float yaw = loc.getYaw();
|
||||
float centeredYaw = Math.round(yaw / 90.0f) * 90.0f;
|
||||
plugin.getConfig().set("locations.lobby.world", loc.getWorld().getName());
|
||||
plugin.getConfig().set("locations.lobby.x", loc.getBlockX() + 0.5);
|
||||
plugin.getConfig().set("locations.lobby.y", (double) loc.getBlockY());
|
||||
plugin.getConfig().set("locations.lobby.z", loc.getBlockZ() + 0.5);
|
||||
plugin.getConfig().set("locations.lobby.yaw", (double) centeredYaw);
|
||||
plugin.getConfig().set("locations.lobby.pitch", 0.0);
|
||||
plugin.saveConfig();
|
||||
player.sendMessage("§a[Bedwars] Waiting lobby spawn point set to your location and saved!");
|
||||
}
|
||||
case "setspawn" -> {
|
||||
if (args.length < 2) {
|
||||
player.sendMessage("§cUsage: /bw setspawn <red|blue|purple|yellow>");
|
||||
return true;
|
||||
}
|
||||
String team = args[1].toLowerCase();
|
||||
if (!isValidTeam(team)) {
|
||||
player.sendMessage("§cInvalid team! Use red, blue, purple, or yellow.");
|
||||
return true;
|
||||
}
|
||||
float yaw = loc.getYaw();
|
||||
float centeredYaw = Math.round(yaw / 90.0f) * 90.0f;
|
||||
plugin.getConfig().set("locations.teams." + team + ".spawn.x", loc.getBlockX() + 0.5);
|
||||
plugin.getConfig().set("locations.teams." + team + ".spawn.y", (double) loc.getBlockY());
|
||||
plugin.getConfig().set("locations.teams." + team + ".spawn.z", loc.getBlockZ() + 0.5);
|
||||
plugin.getConfig().set("locations.teams." + team + ".spawn.yaw", (double) centeredYaw);
|
||||
plugin.getConfig().set("locations.teams." + team + ".spawn.pitch", 0.0);
|
||||
plugin.getConfig().set("locations.teams." + team + ".enabled", true);
|
||||
player.sendMessage("§a[Bedwars] Spawn point for team " + team.toUpperCase() + " set and team ENABLED!");
|
||||
|
||||
// Scanning and auto-setting the matching color Bed block within a 10x5x10 boundary box
|
||||
Location spawnLoc = loc.clone();
|
||||
org.bukkit.Material bedMat = BedwarsTeam.valueOf(team.toUpperCase()).getBedMaterial();
|
||||
Location foundBed = null;
|
||||
|
||||
searchLoop:
|
||||
for (int x = -10; x <= 10; x++) {
|
||||
for (int y = -3; y <= 5; y++) {
|
||||
for (int z = -10; z <= 10; z++) {
|
||||
Block b = spawnLoc.clone().add(x, y, z).getBlock();
|
||||
if (b.getType() == bedMat) {
|
||||
foundBed = b.getLocation();
|
||||
break searchLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (foundBed != null) {
|
||||
plugin.getConfig().set("locations.teams." + team + ".bed.x", foundBed.getX());
|
||||
plugin.getConfig().set("locations.teams." + team + ".bed.y", foundBed.getY());
|
||||
plugin.getConfig().set("locations.teams." + team + ".bed.z", foundBed.getZ());
|
||||
player.sendMessage("§a[Bedwars] Auto-detected matching " + team.toUpperCase() + " bed at " + foundBed.getBlockX() + ", " + foundBed.getBlockY() + ", " + foundBed.getBlockZ() + "!");
|
||||
} else {
|
||||
player.sendMessage("§e[Bedwars] Warning: Matching " + team.toUpperCase() + " bed not found nearby spawn. Remember to set it manually if needed!");
|
||||
}
|
||||
plugin.saveConfig();
|
||||
}
|
||||
case "setbed" -> {
|
||||
if (args.length < 2) {
|
||||
player.sendMessage("§cUsage: /bw setbed <red|blue|purple|yellow>");
|
||||
return true;
|
||||
}
|
||||
String team = args[1].toLowerCase();
|
||||
if (!isValidTeam(team)) {
|
||||
player.sendMessage("§cInvalid team! Use red, blue, purple, or yellow.");
|
||||
return true;
|
||||
}
|
||||
|
||||
Block target = player.getTargetBlockExact(5);
|
||||
if (target == null || !target.getType().name().contains("_BED")) {
|
||||
player.sendMessage("§cYou must be looking at a Bed block within 5 blocks!");
|
||||
return true;
|
||||
}
|
||||
|
||||
Location bedLoc = target.getLocation();
|
||||
plugin.getConfig().set("locations.teams." + team + ".bed.x", bedLoc.getX());
|
||||
plugin.getConfig().set("locations.teams." + team + ".bed.y", bedLoc.getY());
|
||||
plugin.getConfig().set("locations.teams." + team + ".bed.z", bedLoc.getZ());
|
||||
plugin.saveConfig();
|
||||
player.sendMessage("§a[Bedwars] Bed block for team " + team.toUpperCase() + " registered and saved!");
|
||||
}
|
||||
case "setshop" -> {
|
||||
if (args.length < 2) {
|
||||
player.sendMessage("§cUsage: /bw setshop <red|blue|purple|yellow>");
|
||||
return true;
|
||||
}
|
||||
String team = args[1].toLowerCase();
|
||||
if (!isValidTeam(team)) {
|
||||
player.sendMessage("§cInvalid team! Use red, blue, purple, or yellow.");
|
||||
return true;
|
||||
}
|
||||
float yaw = loc.getYaw();
|
||||
float centeredYaw = Math.round(yaw / 90.0f) * 90.0f;
|
||||
plugin.getConfig().set("locations.teams." + team + ".shop.x", loc.getBlockX() + 0.5);
|
||||
plugin.getConfig().set("locations.teams." + team + ".shop.y", (double) loc.getBlockY());
|
||||
plugin.getConfig().set("locations.teams." + team + ".shop.z", loc.getBlockZ() + 0.5);
|
||||
plugin.getConfig().set("locations.teams." + team + ".shop.yaw", (double) centeredYaw);
|
||||
plugin.getConfig().set("locations.teams." + team + ".shop.pitch", 0.0);
|
||||
plugin.saveConfig();
|
||||
player.sendMessage("§a[Bedwars] Shop NPC location for team " + team.toUpperCase() + " set and saved!");
|
||||
}
|
||||
case "setupgrades" -> {
|
||||
if (args.length < 2) {
|
||||
player.sendMessage("§cUsage: /bw setupgrades <red|blue|purple|yellow>");
|
||||
return true;
|
||||
}
|
||||
String team = args[1].toLowerCase();
|
||||
if (!isValidTeam(team)) {
|
||||
player.sendMessage("§cInvalid team! Use red, blue, purple, or yellow.");
|
||||
return true;
|
||||
}
|
||||
float yaw = loc.getYaw();
|
||||
float centeredYaw = Math.round(yaw / 90.0f) * 90.0f;
|
||||
plugin.getConfig().set("locations.teams." + team + ".upgrades.x", loc.getBlockX() + 0.5);
|
||||
plugin.getConfig().set("locations.teams." + team + ".upgrades.y", (double) loc.getBlockY());
|
||||
plugin.getConfig().set("locations.teams." + team + ".upgrades.z", loc.getBlockZ() + 0.5);
|
||||
plugin.getConfig().set("locations.teams." + team + ".upgrades.yaw", (double) centeredYaw);
|
||||
plugin.getConfig().set("locations.teams." + team + ".upgrades.pitch", 0.0);
|
||||
plugin.saveConfig();
|
||||
player.sendMessage("§a[Bedwars] Team Upgrades NPC location for team " + team.toUpperCase() + " set and saved!");
|
||||
}
|
||||
case "setgenerator" -> {
|
||||
if (args.length < 2) {
|
||||
player.sendMessage("§cUsage: /bw setgenerator <red|blue|purple|yellow>");
|
||||
return true;
|
||||
}
|
||||
String team = args[1].toLowerCase();
|
||||
if (!isValidTeam(team)) {
|
||||
player.sendMessage("§cInvalid team! Use red, blue, purple, or yellow.");
|
||||
return true;
|
||||
}
|
||||
plugin.getConfig().set("locations.teams." + team + ".generator.x", loc.getBlockX() + 0.5);
|
||||
plugin.getConfig().set("locations.teams." + team + ".generator.y", (double) loc.getBlockY());
|
||||
plugin.getConfig().set("locations.teams." + team + ".generator.z", loc.getBlockZ() + 0.5);
|
||||
plugin.saveConfig();
|
||||
player.sendMessage("§a[Bedwars] Base spawner (Iron/Gold) location centered and saved for team " + team.toUpperCase() + "!");
|
||||
}
|
||||
case "setenderchest" -> {
|
||||
if (args.length < 2) {
|
||||
player.sendMessage("§cUsage: /bw setenderchest <red|blue|purple|yellow>");
|
||||
return true;
|
||||
}
|
||||
String team = args[1].toLowerCase();
|
||||
if (!isValidTeam(team)) {
|
||||
player.sendMessage("§cInvalid team! Use red, blue, purple, or yellow.");
|
||||
return true;
|
||||
}
|
||||
Block b = loc.getBlock();
|
||||
b.setType(org.bukkit.Material.ENDER_CHEST);
|
||||
|
||||
plugin.getConfig().set("locations.teams." + team + ".enderchest.x", (double) b.getX());
|
||||
plugin.getConfig().set("locations.teams." + team + ".enderchest.y", (double) b.getY());
|
||||
plugin.getConfig().set("locations.teams." + team + ".enderchest.z", (double) b.getZ());
|
||||
plugin.saveConfig();
|
||||
player.sendMessage("§a[Bedwars] Ender Chest for team " + team.toUpperCase() + " placed and saved!");
|
||||
}
|
||||
case "addgenerator" -> {
|
||||
if (args.length < 2) {
|
||||
player.sendMessage("§cUsage: /bw addgenerator <diamond|emerald>");
|
||||
return true;
|
||||
}
|
||||
String type = args[1].toLowerCase();
|
||||
if (!type.equals("diamond") && !type.equals("emerald")) {
|
||||
player.sendMessage("§cInvalid spawner type! Use diamond or emerald.");
|
||||
return true;
|
||||
}
|
||||
|
||||
List<Map<String, Object>> genList = (List<Map<String, Object>>) plugin.getConfig().get("locations.generators");
|
||||
if (genList == null) {
|
||||
genList = new ArrayList<>();
|
||||
}
|
||||
|
||||
Map<String, Object> newGen = new HashMap<>();
|
||||
newGen.put("type", type.toUpperCase());
|
||||
newGen.put("x", loc.getBlockX() + 0.5);
|
||||
newGen.put("y", (double) loc.getBlockY());
|
||||
newGen.put("z", loc.getBlockZ() + 0.5);
|
||||
|
||||
genList.add(newGen);
|
||||
plugin.getConfig().set("locations.generators", genList);
|
||||
plugin.saveConfig();
|
||||
player.sendMessage("§a[Bedwars] Added new " + type.toUpperCase() + " generator centered to block coordinates and saved!");
|
||||
}
|
||||
case "save" -> {
|
||||
plugin.saveConfig();
|
||||
player.sendMessage("§a[Bedwars] Configuration saved to config.yml!");
|
||||
player.sendMessage("§a[Bedwars] Preparing world backup copy as " + loc.getWorld().getName() + "_template...");
|
||||
plugin.getArenaManager().setupTemplate();
|
||||
}
|
||||
case "start" -> {
|
||||
if (plugin.getGameManager().getState() != GameState.LOBBY) {
|
||||
player.sendMessage("§cThe game has already started!");
|
||||
return true;
|
||||
}
|
||||
plugin.getGameManager().startGame();
|
||||
player.sendMessage("§a[Bedwars] Force starting match!");
|
||||
}
|
||||
default -> player.sendMessage("§cUnknown subcommand. Use /bw to see setup options.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isValidTeam(String team) {
|
||||
return team.equals("red") || team.equals("blue") || team.equals("purple") || team.equals("yellow");
|
||||
}
|
||||
|
||||
private void sendHelp(Player player) {
|
||||
player.sendMessage("§d§m================ §b§lBEDWARS SETUP §d§m================");
|
||||
player.sendMessage("§d/bw setlobby §7- Set waiting lobby coordinate");
|
||||
player.sendMessage("§d/bw setspawn <team> §7- Set team player spawn point");
|
||||
player.sendMessage("§d/bw setbed <team> §7- Register team bed (look at bed block)");
|
||||
player.sendMessage("§d/bw setshop <team> §7- Set shop villager position");
|
||||
player.sendMessage("§d/bw setupgrades <team> §7- Set upgrade villager position");
|
||||
player.sendMessage("§d/bw setgenerator <team> §7- Set base Iron/Gold spawner");
|
||||
player.sendMessage("§d/bw setenderchest <team> §7- Place/Set team Ender Chest");
|
||||
player.sendMessage("§d/bw addgenerator <diamond|emerald> §7- Add Diamond/Emerald generator");
|
||||
player.sendMessage("§d/bw save §7- Save config & back up current world as template");
|
||||
player.sendMessage("§d/bw start §7- Force start the game immediately");
|
||||
player.sendMessage("§d§m================================================");
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
|
||||
if (args.length == 1) {
|
||||
List<String> subs = Arrays.asList("setlobby", "setspawn", "setbed", "setshop", "setupgrades", "setgenerator", "setenderchest", "addgenerator", "save", "start", "help");
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String s : subs) {
|
||||
if (s.startsWith(args[0].toLowerCase())) {
|
||||
list.add(s);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
if (args.length == 2) {
|
||||
String sub = args[0].toLowerCase();
|
||||
if (sub.equals("setspawn") || sub.equals("setbed") || sub.equals("setshop") || sub.equals("setupgrades") || sub.equals("setgenerator") || sub.equals("setenderchest")) {
|
||||
List<String> teams = Arrays.asList("red", "blue", "purple", "yellow");
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String t : teams) {
|
||||
if (t.startsWith(args[1].toLowerCase())) {
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
if (sub.equals("addgenerator")) {
|
||||
List<String> types = Arrays.asList("diamond", "emerald");
|
||||
List<String> list = new ArrayList<>();
|
||||
for (String t : types) {
|
||||
if (t.startsWith(args[1].toLowerCase())) {
|
||||
list.add(t);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,132 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public class BedwarsPlugin extends JavaPlugin {
|
||||
|
||||
private static BedwarsPlugin instance;
|
||||
|
||||
// Managers
|
||||
private GameManager gameManager;
|
||||
private ArenaManager arenaManager;
|
||||
private GeneratorManager generatorManager;
|
||||
private ShopManager shopManager;
|
||||
private UpgradesManager upgradesManager;
|
||||
private ScoreboardManager scoreboardManager;
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
instance = this;
|
||||
// Reset active world from pristine template BEFORE Bukkit loads the world
|
||||
new ArenaManager(this).onLoadCopy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
|
||||
// Save default config
|
||||
saveDefaultConfig();
|
||||
|
||||
// Disable advancements gamerule for all loaded worlds at startup
|
||||
for (org.bukkit.World world : Bukkit.getWorlds()) {
|
||||
world.setGameRule(org.bukkit.GameRule.ANNOUNCE_ADVANCEMENTS, false);
|
||||
}
|
||||
|
||||
// Instantiate Managers
|
||||
this.arenaManager = new ArenaManager(this);
|
||||
this.gameManager = new GameManager(this);
|
||||
this.generatorManager = new GeneratorManager(this);
|
||||
this.shopManager = new ShopManager(this);
|
||||
this.upgradesManager = new UpgradesManager(this);
|
||||
this.scoreboardManager = new ScoreboardManager(this);
|
||||
|
||||
// Register outgoing plugin messaging channels for Velocity Proxy redirection compatibility
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "bungeecord:main");
|
||||
getServer().getMessenger().registerOutgoingPluginChannel(this, "nexoria:main");
|
||||
|
||||
// Load the active game world if it is different from the default world
|
||||
String worldName = getConfig().getString("world-name", "world");
|
||||
if (Bukkit.getWorld(worldName) == null) {
|
||||
getLogger().info("Loading Bedwars game world '" + worldName + "'...");
|
||||
org.bukkit.World w = Bukkit.createWorld(new org.bukkit.WorldCreator(worldName));
|
||||
if (w != null) {
|
||||
w.setGameRule(org.bukkit.GameRule.ANNOUNCE_ADVANCEMENTS, false);
|
||||
}
|
||||
} else {
|
||||
org.bukkit.World w = Bukkit.getWorld(worldName);
|
||||
if (w != null) {
|
||||
w.setGameRule(org.bukkit.GameRule.ANNOUNCE_ADVANCEMENTS, false);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize game manager values
|
||||
this.gameManager.init();
|
||||
|
||||
// Build waiting lobby glass platform cage
|
||||
this.arenaManager.createWaitingLobby();
|
||||
|
||||
// Register Commands
|
||||
PluginCommand bwCmd = getCommand("bw");
|
||||
if (bwCmd != null) {
|
||||
BedwarsCommand executor = new BedwarsCommand(this);
|
||||
bwCmd.setExecutor(executor);
|
||||
bwCmd.setTabCompleter(executor);
|
||||
}
|
||||
|
||||
// Register Listeners
|
||||
getServer().getPluginManager().registerEvents(new GameListener(this), this);
|
||||
getServer().getPluginManager().registerEvents(new ShopListener(this), this);
|
||||
|
||||
getLogger().info("================================================");
|
||||
getLogger().info(" Bedwars Plugin has been successfully enabled! ");
|
||||
getLogger().info(" Compatible with 1.21.4+ and Nexoria Proxy ");
|
||||
getLogger().info("================================================");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
// Cleanup all floating Text Displays (Holograms) to prevent visual dupes
|
||||
if (generatorManager != null) {
|
||||
generatorManager.cleanup();
|
||||
}
|
||||
|
||||
// Unregister plugin channels cleanly
|
||||
getServer().getMessenger().unregisterOutgoingPluginChannel(this, "BungeeCord");
|
||||
getServer().getMessenger().unregisterOutgoingPluginChannel(this, "bungeecord:main");
|
||||
getServer().getMessenger().unregisterOutgoingPluginChannel(this, "nexoria:main");
|
||||
|
||||
getLogger().info("Bedwars Plugin has been successfully disabled!");
|
||||
}
|
||||
|
||||
public static BedwarsPlugin getInstance() {
|
||||
return instance;
|
||||
}
|
||||
|
||||
public GameManager getGameManager() {
|
||||
return gameManager;
|
||||
}
|
||||
|
||||
public ArenaManager getArenaManager() {
|
||||
return arenaManager;
|
||||
}
|
||||
|
||||
public GeneratorManager getGeneratorManager() {
|
||||
return generatorManager;
|
||||
}
|
||||
|
||||
public ShopManager getShopManager() {
|
||||
return shopManager;
|
||||
}
|
||||
|
||||
public UpgradesManager getUpgradesManager() {
|
||||
return upgradesManager;
|
||||
}
|
||||
|
||||
public ScoreboardManager getScoreboardManager() {
|
||||
return scoreboardManager;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
|
||||
public enum BedwarsTeam {
|
||||
RED("Red", ChatColor.RED, "§c[RED] ", Material.RED_WOOL, Material.RED_BED),
|
||||
BLUE("Blue", ChatColor.BLUE, "§9[BLUE] ", Material.BLUE_WOOL, Material.BLUE_BED),
|
||||
PURPLE("Purple", ChatColor.DARK_PURPLE, "§5[PURPLE] ", Material.PURPLE_WOOL, Material.PURPLE_BED),
|
||||
YELLOW("Yellow", ChatColor.YELLOW, "§e[YELLOW] ", Material.YELLOW_WOOL, Material.YELLOW_BED);
|
||||
|
||||
private final String name;
|
||||
private final ChatColor color;
|
||||
private final String prefix;
|
||||
private final Material woolMaterial;
|
||||
private final Material bedMaterial;
|
||||
|
||||
BedwarsTeam(String name, ChatColor color, String prefix, Material woolMaterial, Material bedMaterial) {
|
||||
this.name = name;
|
||||
this.color = color;
|
||||
this.prefix = prefix;
|
||||
this.woolMaterial = woolMaterial;
|
||||
this.bedMaterial = bedMaterial;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public ChatColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public String getPrefix() {
|
||||
return prefix;
|
||||
}
|
||||
|
||||
public Material getWoolMaterial() {
|
||||
return woolMaterial;
|
||||
}
|
||||
|
||||
public Material getBedMaterial() {
|
||||
return bedMaterial;
|
||||
}
|
||||
|
||||
public String getColorizedName() {
|
||||
return color + name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,823 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.*;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.data.type.Bed;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.block.BlockBreakEvent;
|
||||
import org.bukkit.event.block.BlockPlaceEvent;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent;
|
||||
import org.bukkit.event.entity.FoodLevelChangeEvent;
|
||||
import org.bukkit.event.entity.EntityPickupItemEvent;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.bukkit.event.player.PlayerMoveEvent;
|
||||
import org.bukkit.event.player.PlayerQuitEvent;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
public class GameListener implements Listener {
|
||||
|
||||
private final BedwarsPlugin plugin;
|
||||
private final java.util.Map<java.util.UUID, Long> fireballCooldowns = new java.util.HashMap<>();
|
||||
|
||||
public GameListener(BedwarsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerJoin(PlayerJoinEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
int online = Bukkit.getOnlinePlayers().size();
|
||||
int max = Bukkit.getMaxPlayers();
|
||||
event.setJoinMessage("§a[+] §7" + player.getName() + " §8[" + online + "/" + max + "]");
|
||||
|
||||
// Setup Scoreboard
|
||||
plugin.getScoreboardManager().setupScoreboard(player);
|
||||
|
||||
GameManager gm = plugin.getGameManager();
|
||||
gm.updateTabName(player);
|
||||
if (gm.getState() == GameState.LOBBY) {
|
||||
player.setGameMode(GameMode.SURVIVAL);
|
||||
player.setHealth(20.0);
|
||||
player.setFoodLevel(20);
|
||||
player.getInventory().clear();
|
||||
player.getEnderChest().clear();
|
||||
|
||||
// Clear potion effects
|
||||
for (org.bukkit.potion.PotionEffect effect : player.getActivePotionEffects()) {
|
||||
player.removePotionEffect(effect.getType());
|
||||
}
|
||||
|
||||
// Teleport to lobby spawn
|
||||
teleportToLobby(player);
|
||||
gm.checkStart();
|
||||
} else {
|
||||
// Join as spectator if game is already running
|
||||
gm.addSpectator(player);
|
||||
player.sendMessage("§eMatch in progress! You are spectating.");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerQuit(PlayerQuitEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
int online = Bukkit.getOnlinePlayers().size() - 1;
|
||||
int max = Bukkit.getMaxPlayers();
|
||||
event.setQuitMessage("§c[-] §7" + player.getName() + " §8[" + online + "/" + max + "]");
|
||||
|
||||
plugin.getScoreboardManager().removeScoreboard(player);
|
||||
plugin.getShopManager().resetPlayerShopData(player);
|
||||
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (online == 0 && gm.getState() == GameState.PLAYING) {
|
||||
gm.resetGameImmediately();
|
||||
} else if (gm.getState() == GameState.PLAYING) {
|
||||
gm.handlePlayerQuit(player);
|
||||
}
|
||||
}
|
||||
|
||||
private void teleportToLobby(Player player) {
|
||||
if (plugin.getConfig().contains("locations.lobby")) {
|
||||
String worldName = plugin.getConfig().getString("locations.lobby.world", "world");
|
||||
World w = Bukkit.getWorld(worldName);
|
||||
if (w != null) {
|
||||
double x = plugin.getConfig().getDouble("locations.lobby.x");
|
||||
double y = plugin.getConfig().getDouble("locations.lobby.y");
|
||||
double z = plugin.getConfig().getDouble("locations.lobby.z");
|
||||
float yaw = (float) plugin.getConfig().getDouble("locations.lobby.yaw");
|
||||
float pitch = (float) plugin.getConfig().getDouble("locations.lobby.pitch");
|
||||
player.teleport(new Location(w, x, y, z, yaw, pitch));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Fallback
|
||||
player.teleport(player.getWorld().getSpawnLocation());
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPlace(BlockPlaceEvent event) {
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (gm.getState() != GameState.PLAYING) {
|
||||
if (!event.getPlayer().hasPermission("bedwars.admin")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (gm.isSpectator(player)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Block block = event.getBlockPlaced();
|
||||
|
||||
// Custom TNT auto-explode logic
|
||||
if (block.getType() == Material.TNT) {
|
||||
event.setCancelled(true);
|
||||
|
||||
// Deduct 1 TNT from hand
|
||||
ItemStack handItem = event.getItemInHand();
|
||||
if (handItem != null) {
|
||||
handItem.setAmount(handItem.getAmount() - 1);
|
||||
}
|
||||
|
||||
// Spawn primed TNT
|
||||
Location spawnLoc = block.getLocation().add(0.5, 0.5, 0.5);
|
||||
org.bukkit.entity.TNTPrimed tnt = spawnLoc.getWorld().spawn(spawnLoc, org.bukkit.entity.TNTPrimed.class);
|
||||
tnt.setFuseTicks(40); // 2 seconds fuse
|
||||
tnt.setSource(player);
|
||||
|
||||
// Play ignite sound
|
||||
player.getWorld().playSound(spawnLoc, Sound.ENTITY_TNT_PRIMED, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
// Track player placed blocks so they can be broken
|
||||
plugin.getArenaManager().trackBlockPlace(block);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockBreak(BlockBreakEvent event) {
|
||||
GameManager gm = plugin.getGameManager();
|
||||
Player player = event.getPlayer();
|
||||
|
||||
if (player.getGameMode() == GameMode.CREATIVE && player.hasPermission("bedwars.admin")) {
|
||||
return; // Admins bypass
|
||||
}
|
||||
|
||||
if (gm.getState() != GameState.PLAYING) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (gm.isSpectator(player)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Block block = event.getBlock();
|
||||
Material mat = block.getType();
|
||||
|
||||
// 1. Check if Bed is broken
|
||||
if (mat.name().contains("_BED")) {
|
||||
event.setCancelled(true); // Don't drop item, handle custom deletion
|
||||
|
||||
Location breakLoc = block.getLocation();
|
||||
BedwarsTeam brokenTeam = null;
|
||||
|
||||
// Search for matching team bed coordinate
|
||||
for (BedwarsTeam team : BedwarsTeam.values()) {
|
||||
if (gm.isTeamEnabled(team)) {
|
||||
String path = "locations.teams." + team.getName().toLowerCase() + ".bed";
|
||||
if (plugin.getConfig().contains(path)) {
|
||||
double x = plugin.getConfig().getDouble(path + ".x");
|
||||
double y = plugin.getConfig().getDouble(path + ".y");
|
||||
double z = plugin.getConfig().getDouble(path + ".z");
|
||||
Location bedLoc = new Location(breakLoc.getWorld(), x, y, z);
|
||||
|
||||
// Distance check <= 2.25 blocks squared to cover both halves of the bed
|
||||
if (breakLoc.distanceSquared(bedLoc) <= 2.5) {
|
||||
brokenTeam = team;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (brokenTeam != null) {
|
||||
BedwarsTeam breakerTeam = gm.getPlayerTeam(player);
|
||||
if (breakerTeam == brokenTeam) {
|
||||
player.sendMessage("§cYou cannot break your own bed!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Bed is broken!
|
||||
gm.setBedBroken(brokenTeam, true);
|
||||
gm.addBedBroken(player);
|
||||
|
||||
// Silently erase both halves of the bed block in world
|
||||
if (block.getBlockData() instanceof Bed bedData) {
|
||||
Block otherHalf = block.getRelative(bedData.getFacing());
|
||||
if (otherHalf.getType().name().contains("_BED")) {
|
||||
otherHalf.setType(Material.AIR);
|
||||
}
|
||||
}
|
||||
block.setType(Material.AIR);
|
||||
|
||||
// Global Announce
|
||||
Bukkit.broadcastMessage("§c§lBED DESTRUCTION!");
|
||||
Bukkit.broadcastMessage(" " + brokenTeam.getColorizedName() + " Bed §fwas destroyed by " + breakerTeam.getColor() + player.getName() + "!");
|
||||
|
||||
// Title and Sound
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
p.playSound(p.getLocation(), Sound.ENTITY_ENDER_DRAGON_GROWL, 0.8f, 1.0f);
|
||||
BedwarsTeam pTeam = gm.getPlayerTeam(p);
|
||||
if (pTeam == brokenTeam) {
|
||||
p.sendTitle("§c§lBED DESTROYED!", "§fYou will no longer respawn!", 10, 60, 10);
|
||||
}
|
||||
}
|
||||
gm.checkWinner();
|
||||
} else {
|
||||
player.sendMessage("§cThis is an un-registered bed block!");
|
||||
block.setType(Material.AIR);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Standard block break (Must be player placed block!)
|
||||
if (plugin.getArenaManager().isPlayerPlacedBlock(block)) {
|
||||
plugin.getArenaManager().removeTrackedBlock(block);
|
||||
} else {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage("§cYou can only break blocks placed by players!");
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerMove(PlayerMoveEvent event) {
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (gm.getState() != GameState.PLAYING) return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
if (gm.isSpectator(player)) return;
|
||||
|
||||
// Void Fall Detector
|
||||
if (player.getLocation().getY() <= -20.0) {
|
||||
// Trigger instant death sequence
|
||||
Player killer = gm.getLastAttacker(player);
|
||||
gm.handlePlayerDeath(player, killer);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityDamage(EntityDamageEvent event) {
|
||||
if (!(event.getEntity() instanceof Player player)) return;
|
||||
|
||||
GameManager gm = plugin.getGameManager();
|
||||
|
||||
// 1. Lobby and ending protection
|
||||
if (gm.getState() != GameState.PLAYING) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Spectator protection
|
||||
if (gm.isSpectator(player)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Intercept death and trigger custom Respawn sequences instead of Vanilla screen
|
||||
if (player.getHealth() - event.getFinalDamage() <= 0) {
|
||||
event.setCancelled(true);
|
||||
|
||||
Player killer = null;
|
||||
if (event instanceof EntityDamageByEntityEvent entityEvent) {
|
||||
if (entityEvent.getDamager() instanceof Player p) {
|
||||
killer = p;
|
||||
} else if (entityEvent.getDamager() instanceof Projectile proj) {
|
||||
if (proj.getShooter() instanceof Player p) {
|
||||
killer = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (killer == null) {
|
||||
killer = gm.getLastAttacker(player);
|
||||
}
|
||||
|
||||
gm.handlePlayerDeath(player, killer);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
|
||||
if (!(event.getEntity() instanceof Player victim)) return;
|
||||
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (gm.getState() != GameState.PLAYING) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent spectator damage
|
||||
if (gm.isSpectator(victim)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
org.bukkit.entity.Entity damager = event.getDamager();
|
||||
Player attacker = null;
|
||||
LastDamageType type = LastDamageType.OTHER;
|
||||
|
||||
// 1. Handle Fireball Explosion / Direct Damage
|
||||
if (damager instanceof org.bukkit.entity.Fireball fireball) {
|
||||
Player shooter = fireball.getShooter() instanceof Player ? (Player) fireball.getShooter() : null;
|
||||
if (shooter != null) {
|
||||
attacker = shooter;
|
||||
type = LastDamageType.FIREBALL;
|
||||
|
||||
// Teammate and self-damage handling
|
||||
if (shooter.equals(victim)) {
|
||||
// Self fireball damage is scaled down to 1.0 (0.5 heart)
|
||||
event.setDamage(1.0);
|
||||
} else {
|
||||
BedwarsTeam t1 = gm.getPlayerTeam(shooter);
|
||||
BedwarsTeam t2 = gm.getPlayerTeam(victim);
|
||||
if (t1 != null && t1 == t2) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
// Enemy fireball damage scaled down to max 3.0 (1.5 hearts)
|
||||
event.setDamage(Math.min(event.getDamage(), 3.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. Handle TNT Explosion Damage
|
||||
else if (damager instanceof org.bukkit.entity.TNTPrimed tnt) {
|
||||
Player source = tnt.getSource() instanceof Player ? (Player) tnt.getSource() : null;
|
||||
if (source != null) {
|
||||
attacker = source;
|
||||
type = LastDamageType.TNT;
|
||||
|
||||
// Teammate and self-damage handling
|
||||
if (source.equals(victim)) {
|
||||
// Self TNT damage is scaled down to 2.0 (1 heart)
|
||||
event.setDamage(2.0);
|
||||
} else {
|
||||
BedwarsTeam t1 = gm.getPlayerTeam(source);
|
||||
BedwarsTeam t2 = gm.getPlayerTeam(victim);
|
||||
if (t1 != null && t1 == t2) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
// Enemy TNT damage scaled down to max 5.0 (2.5 hearts)
|
||||
event.setDamage(Math.min(event.getDamage(), 5.0));
|
||||
}
|
||||
}
|
||||
}
|
||||
// 3. Handle physical hits (Melee) or Bow Projectiles
|
||||
else {
|
||||
if (damager instanceof Player p) {
|
||||
attacker = p;
|
||||
type = LastDamageType.MELEE;
|
||||
} else if (damager instanceof Projectile proj) {
|
||||
if (proj.getShooter() instanceof Player p) {
|
||||
attacker = p;
|
||||
type = LastDamageType.PROJECTILE;
|
||||
}
|
||||
}
|
||||
|
||||
if (attacker != null) {
|
||||
// Self damage from standard physical hits is impossible but check anyway
|
||||
if (attacker.equals(victim)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Friendly Fire block
|
||||
BedwarsTeam t1 = gm.getPlayerTeam(attacker);
|
||||
BedwarsTeam t2 = gm.getPlayerTeam(victim);
|
||||
if (t1 != null && t1 == t2) {
|
||||
event.setCancelled(true);
|
||||
attacker.sendMessage("§cYou cannot attack your teammate!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Apply general checks and tracking if there's a valid attacker
|
||||
if (attacker != null) {
|
||||
if (gm.isSpectator(attacker)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
// Track last attacker for kill attribution
|
||||
gm.setLastAttacker(victim, attacker, type);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onFoodLevelChange(FoodLevelChangeEvent event) {
|
||||
// Disable hunger during lobby or match
|
||||
event.setCancelled(true);
|
||||
if (event.getEntity() instanceof Player player) {
|
||||
player.setFoodLevel(20);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPickupItem(EntityPickupItemEvent event) {
|
||||
if (event.getEntity() instanceof Player player) {
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (gm.isSpectator(player)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply sharpness automatically when sword is picked up
|
||||
plugin.getUpgradesManager().applyTeamUpgrades(player);
|
||||
|
||||
// Generator resource sharing (split) logic
|
||||
Material type = event.getItem().getItemStack().getType();
|
||||
if (type == Material.IRON_INGOT || type == Material.GOLD_INGOT ||
|
||||
type == Material.DIAMOND || type == Material.EMERALD) {
|
||||
|
||||
// Only split resources that were spawned by a generator, preventing duplication on player drops
|
||||
org.bukkit.NamespacedKey key = new org.bukkit.NamespacedKey(plugin, "generator_spawned");
|
||||
if (!event.getItem().getPersistentDataContainer().has(key, org.bukkit.persistence.PersistentDataType.BYTE)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Location pickupLoc = event.getItem().getLocation();
|
||||
Generator nearbyGen = null;
|
||||
for (Generator gen : plugin.getGeneratorManager().getActiveGenerators()) {
|
||||
if (gen.getLocation().getWorld().equals(pickupLoc.getWorld()) &&
|
||||
gen.getLocation().distanceSquared(pickupLoc) <= 25.0) { // 5 blocks radius
|
||||
nearbyGen = gen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nearbyGen != null) {
|
||||
int amount = event.getItem().getItemStack().getAmount();
|
||||
BedwarsTeam team = plugin.getGameManager().getPlayerTeam(player);
|
||||
if (team != null) {
|
||||
for (Player other : player.getWorld().getPlayers()) {
|
||||
if (other.equals(player)) continue;
|
||||
if (plugin.getGameManager().isSpectator(other)) continue;
|
||||
|
||||
// Check if other player is teammate
|
||||
if (plugin.getGameManager().getPlayerTeam(other) == team) {
|
||||
// Check if other player is near the picking player (within 3.5 blocks)
|
||||
if (other.getLocation().distanceSquared(player.getLocation()) <= 12.25) {
|
||||
// Give them the same item!
|
||||
ItemStack copy = new ItemStack(type, amount);
|
||||
other.getInventory().addItem(copy);
|
||||
other.playSound(other.getLocation(), Sound.ENTITY_ITEM_PICKUP, 0.5f, 1.5f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (event.getWhoClicked() instanceof Player player) {
|
||||
GameManager gm = plugin.getGameManager();
|
||||
|
||||
// Handle Teleporter inventory click
|
||||
if (event.getView().getTitle().equals("§8Teleporter")) {
|
||||
event.setCancelled(true);
|
||||
ItemStack clicked = event.getCurrentItem();
|
||||
if (clicked != null && clicked.getType() == Material.PLAYER_HEAD) {
|
||||
org.bukkit.inventory.meta.SkullMeta meta = (org.bukkit.inventory.meta.SkullMeta) clicked.getItemMeta();
|
||||
if (meta != null && meta.getOwningPlayer() != null) {
|
||||
Player target = Bukkit.getPlayer(meta.getOwningPlayer().getUniqueId());
|
||||
if (target != null && target.isOnline()) {
|
||||
player.teleport(target.getLocation());
|
||||
player.sendMessage("§aTeleported to " + clicked.getItemMeta().getDisplayName() + "§a!");
|
||||
player.closeInventory();
|
||||
} else {
|
||||
player.sendMessage("§cThat player is no longer online!");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Block spectators from doing anything in inventories
|
||||
if (gm.isSpectator(player)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Block taking off armor
|
||||
if (event.getSlotType() == org.bukkit.event.inventory.InventoryType.SlotType.ARMOR) {
|
||||
event.setCancelled(true);
|
||||
player.sendMessage("§cYou cannot take off your team armor!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply team upgrades when inventory changes or items are moved
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||
plugin.getUpgradesManager().applyTeamUpgrades(player);
|
||||
}, 1L);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCreatureSpawn(org.bukkit.event.entity.CreatureSpawnEvent event) {
|
||||
String worldName = plugin.getConfig().getString("world-name", "world");
|
||||
if (event.getEntity().getWorld().getName().equalsIgnoreCase(worldName)) {
|
||||
// Cancel all spawns except command or custom (e.g. Villagers, utility mobs)
|
||||
org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason = event.getSpawnReason();
|
||||
if (reason != org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CUSTOM &&
|
||||
reason != org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.COMMAND) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onBlockPhysics(org.bukkit.event.block.BlockPhysicsEvent event) {
|
||||
Material mat = event.getChangedType();
|
||||
String name = mat.name();
|
||||
if (name.contains("CONCRETE_POWDER") || name.contains("SAND") || name.equals("GRAVEL")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onFallingBlockSpawn(org.bukkit.event.entity.EntitySpawnEvent event) {
|
||||
if (event.getEntity() instanceof org.bukkit.entity.FallingBlock fallingBlock) {
|
||||
Material mat = fallingBlock.getBlockData().getMaterial();
|
||||
String name = mat.name();
|
||||
if (name.contains("CONCRETE_POWDER") || name.contains("SAND") || name.equals("GRAVEL")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkLoad(org.bukkit.event.world.ChunkLoadEvent event) {
|
||||
String worldName = plugin.getConfig().getString("world-name", "world");
|
||||
if (event.getChunk().getWorld().getName().equalsIgnoreCase(worldName)) {
|
||||
for (org.bukkit.entity.Entity entity : event.getChunk().getEntities()) {
|
||||
if (entity instanceof org.bukkit.entity.Mob || entity instanceof org.bukkit.entity.Ambient) {
|
||||
if (entity.getType() == org.bukkit.entity.EntityType.VILLAGER) {
|
||||
continue;
|
||||
}
|
||||
entity.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerAdvancementDone(org.bukkit.event.player.PlayerAdvancementDoneEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
org.bukkit.advancement.Advancement advancement = event.getAdvancement();
|
||||
org.bukkit.advancement.AdvancementProgress progress = player.getAdvancementProgress(advancement);
|
||||
for (String criteria : progress.getAwardedCriteria()) {
|
||||
progress.revokeCriteria(criteria);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onWorldLoad(org.bukkit.event.world.WorldLoadEvent event) {
|
||||
event.getWorld().setGameRule(org.bukkit.GameRule.ANNOUNCE_ADVANCEMENTS, false);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityExplode(org.bukkit.event.entity.EntityExplodeEvent event) {
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (gm.getState() != GameState.PLAYING) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
org.bukkit.entity.Entity exploder = event.getEntity();
|
||||
boolean isFireball = exploder instanceof org.bukkit.entity.Fireball;
|
||||
boolean isTNT = exploder instanceof org.bukkit.entity.TNTPrimed;
|
||||
|
||||
// Apply custom explosion propulsion to nearby players
|
||||
if (isFireball || isTNT) {
|
||||
Location explosionLoc = event.getLocation();
|
||||
double radius = isFireball ? 5.5 : 6.5;
|
||||
double maxPower = isFireball ? 1.65 : 2.1;
|
||||
double verticalBoost = isFireball ? 0.75 : 0.95;
|
||||
|
||||
for (Player player : explosionLoc.getWorld().getPlayers()) {
|
||||
if (gm.isSpectator(player)) continue;
|
||||
|
||||
double distance = player.getLocation().distance(explosionLoc);
|
||||
if (distance <= radius) {
|
||||
// Calculate custom knockback vector
|
||||
org.bukkit.util.Vector direction = player.getLocation().toVector().subtract(explosionLoc.toVector());
|
||||
if (distance < 0.1) {
|
||||
direction = new org.bukkit.util.Vector(0, 1, 0);
|
||||
distance = 0.1;
|
||||
} else {
|
||||
direction.normalize();
|
||||
}
|
||||
|
||||
// Power calculation with distance falloff but strong baseline (Hypixel style)
|
||||
double ratio = 1.0 - (distance / radius);
|
||||
double power = maxPower * (0.45 + 0.55 * ratio);
|
||||
|
||||
org.bukkit.util.Vector velocity = direction.multiply(power);
|
||||
|
||||
// Upward launch enhancement
|
||||
double yVal = direction.getY() * verticalBoost;
|
||||
if (yVal < 0) yVal = 0;
|
||||
double finalY = Math.max(0.42, yVal + 0.38 * ratio);
|
||||
velocity.setY(finalY);
|
||||
|
||||
// Smooth blending with player's current horizontal momentum
|
||||
org.bukkit.util.Vector currentVel = player.getVelocity();
|
||||
double blendedX = currentVel.getX() * 0.45 + velocity.getX();
|
||||
double blendedZ = currentVel.getZ() * 0.45 + velocity.getZ();
|
||||
|
||||
org.bukkit.util.Vector finalVelocity = new org.bukkit.util.Vector(blendedX, finalY, blendedZ);
|
||||
|
||||
// Clamp to prevent extreme/glitchy speeds
|
||||
double maxSpeed = isFireball ? 3.0 : 3.8;
|
||||
if (finalVelocity.length() > maxSpeed) {
|
||||
finalVelocity.normalize().multiply(maxSpeed);
|
||||
}
|
||||
|
||||
// Schedule velocity change on next tick to cleanly overwrite vanilla explosion knockback
|
||||
Bukkit.getScheduler().runTaskLater(plugin, () -> {
|
||||
player.setVelocity(finalVelocity);
|
||||
}, 1L);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Only allow breaking player placed blocks, and exclude blast-proof blocks (Glass and Obsidian)
|
||||
java.util.Iterator<Block> iterator = event.blockList().iterator();
|
||||
while (iterator.hasNext()) {
|
||||
Block block = iterator.next();
|
||||
Material type = block.getType();
|
||||
if (type == Material.GLASS || type == Material.OBSIDIAN) {
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
if (!plugin.getArenaManager().isPlayerPlacedBlock(block)) {
|
||||
iterator.remove();
|
||||
} else {
|
||||
// Remove from tracking since it will be destroyed
|
||||
plugin.getArenaManager().removeTrackedBlock(block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteract(org.bukkit.event.player.PlayerInteractEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (gm.isSpectator(player)) {
|
||||
event.setCancelled(true);
|
||||
ItemStack item = event.getItem();
|
||||
if (item != null) {
|
||||
if (item.getType() == Material.COMPASS) {
|
||||
openTeleporterGui(player);
|
||||
} else if (item.getType() == Material.RED_BED) {
|
||||
gm.sendToLobby(player);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (event.getAction() == org.bukkit.event.block.Action.RIGHT_CLICK_AIR ||
|
||||
event.getAction() == org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK) {
|
||||
|
||||
ItemStack item = event.getItem();
|
||||
|
||||
if (item != null && item.getType() == Material.FIRE_CHARGE) {
|
||||
// Cancel setting fire to blocks
|
||||
event.setCancelled(true);
|
||||
|
||||
if (gm.getState() != GameState.PLAYING || gm.isSpectator(player)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Cooldown check (500ms)
|
||||
long now = System.currentTimeMillis();
|
||||
if (fireballCooldowns.containsKey(player.getUniqueId())) {
|
||||
long lastShoot = fireballCooldowns.get(player.getUniqueId());
|
||||
if (now - lastShoot < 500) {
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_ENDER_DRAGON_FLAP, 0.5f, 1.5f);
|
||||
return; // Silent cancel to prevent spam
|
||||
}
|
||||
}
|
||||
fireballCooldowns.put(player.getUniqueId(), now);
|
||||
|
||||
// Shoot fireball
|
||||
org.bukkit.entity.Fireball fireball = player.launchProjectile(org.bukkit.entity.Fireball.class);
|
||||
fireball.setYield(2.5f); // Safe explosion size
|
||||
fireball.setIsIncendiary(false); // Don't set fires
|
||||
fireball.setShooter(player);
|
||||
|
||||
// Apply straight and fast velocity like Hypixel
|
||||
org.bukkit.util.Vector direction = player.getLocation().getDirection();
|
||||
fireball.setDirection(direction);
|
||||
fireball.setVelocity(direction.multiply(1.6));
|
||||
|
||||
// Play shoot sound
|
||||
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_GHAST_SHOOT, 1.0f, 1.0f);
|
||||
|
||||
// Deduct 1 fireball
|
||||
int amount = item.getAmount();
|
||||
if (amount > 1) {
|
||||
item.setAmount(amount - 1);
|
||||
} else {
|
||||
player.getInventory().setItemInMainHand(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onCraftItem(org.bukkit.event.inventory.CraftItemEvent event) {
|
||||
// Disable all crafting
|
||||
event.setCancelled(true);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPrepareCraft(org.bukkit.event.inventory.PrepareItemCraftEvent event) {
|
||||
// Clear crafting result to disable personal 2x2 crafting in player inventory
|
||||
event.getInventory().setResult(new org.bukkit.inventory.ItemStack(org.bukkit.Material.AIR));
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onAdvancementDone(org.bukkit.event.player.PlayerAdvancementDoneEvent event) {
|
||||
// Silently revoke all advancements immediately so players never earn them or get spammed
|
||||
final Player player = event.getPlayer();
|
||||
final org.bukkit.advancement.Advancement advancement = event.getAdvancement();
|
||||
final org.bukkit.advancement.AdvancementProgress progress = player.getAdvancementProgress(advancement);
|
||||
for (String criteria : progress.getAwardedCriteria()) {
|
||||
Bukkit.getScheduler().runTask(plugin, () -> progress.revokeCriteria(criteria));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerDropItem(org.bukkit.event.player.PlayerDropItemEvent event) {
|
||||
Player player = event.getPlayer();
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (gm.isSpectator(player)) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void openTeleporterGui(Player player) {
|
||||
java.util.List<Player> alivePlayers = new java.util.ArrayList<>();
|
||||
GameManager gm = plugin.getGameManager();
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
if (!gm.isSpectator(p)) {
|
||||
alivePlayers.add(p);
|
||||
}
|
||||
}
|
||||
|
||||
if (alivePlayers.isEmpty()) {
|
||||
player.sendMessage("§cNo active players to spectate!");
|
||||
return;
|
||||
}
|
||||
|
||||
int size = ((alivePlayers.size() / 9) + 1) * 9;
|
||||
if (size > 54) size = 54;
|
||||
org.bukkit.inventory.Inventory inv = Bukkit.createInventory(null, size, "§8Teleporter");
|
||||
|
||||
for (int i = 0; i < Math.min(alivePlayers.size(), size); i++) {
|
||||
Player target = alivePlayers.get(i);
|
||||
ItemStack head = new ItemStack(Material.PLAYER_HEAD);
|
||||
org.bukkit.inventory.meta.SkullMeta meta = (org.bukkit.inventory.meta.SkullMeta) head.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setOwningPlayer(target);
|
||||
meta.setDisplayName(gm.getFormattedName(target));
|
||||
java.util.List<String> lore = new java.util.ArrayList<>();
|
||||
lore.add("§7Click to teleport to player");
|
||||
meta.setLore(lore);
|
||||
head.setItemMeta(meta);
|
||||
}
|
||||
inv.setItem(i, head);
|
||||
}
|
||||
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onEntityRegainHealth(org.bukkit.event.entity.EntityRegainHealthEvent event) {
|
||||
if (event.getEntity() instanceof Player player) {
|
||||
GameManager gm = plugin.getGameManager();
|
||||
if (gm.getState() == GameState.PLAYING && !gm.isSpectator(player)) {
|
||||
if (event.getRegainReason() == org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason.SATIATED) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,7 @@
|
||||
package com.bedwars;
|
||||
|
||||
public enum GameState {
|
||||
LOBBY,
|
||||
PLAYING,
|
||||
ENDING
|
||||
}
|
||||
@@ -0,0 +1,191 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Particle;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Item;
|
||||
import org.bukkit.entity.TextDisplay;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
public class Generator {
|
||||
|
||||
private final Location location;
|
||||
private final GeneratorType type;
|
||||
private int ticksUntilSpawn;
|
||||
private final int maxSpawnTicks;
|
||||
private int upgradeLevel = 1; // Used for base generator upgrades
|
||||
private TextDisplay textDisplay;
|
||||
|
||||
public Generator(Location location, GeneratorType type, int maxSpawnTicks) {
|
||||
this.location = location;
|
||||
this.type = type;
|
||||
this.maxSpawnTicks = maxSpawnTicks;
|
||||
this.ticksUntilSpawn = maxSpawnTicks;
|
||||
spawnHologram();
|
||||
}
|
||||
|
||||
private void spawnHologram() {
|
||||
if (type == GeneratorType.IRON_GOLD) {
|
||||
return; // No hologram needed for base spawners
|
||||
}
|
||||
|
||||
// Spawn a TextDisplay entity 2 blocks above the generator, perfectly centered
|
||||
double cx = Math.floor(location.getX()) + 0.5;
|
||||
double cy = location.getY() + 2.0;
|
||||
double cz = Math.floor(location.getZ()) + 0.5;
|
||||
Location displayLoc = new Location(location.getWorld(), cx, cy, cz);
|
||||
if (displayLoc.getWorld() != null) {
|
||||
// Delete any existing text display entities nearby first to avoid duplicates
|
||||
displayLoc.getWorld().getNearbyEntities(displayLoc, 1, 2, 1).forEach(entity -> {
|
||||
if (entity instanceof TextDisplay) {
|
||||
entity.remove();
|
||||
}
|
||||
});
|
||||
|
||||
textDisplay = displayLoc.getWorld().spawn(displayLoc, TextDisplay.class);
|
||||
textDisplay.setBillboard(TextDisplay.Billboard.CENTER);
|
||||
textDisplay.setGravity(false);
|
||||
textDisplay.setInvulnerable(true);
|
||||
textDisplay.setPersistent(false);
|
||||
|
||||
// Set transparent background
|
||||
textDisplay.setBackgroundColor(org.bukkit.Color.fromARGB(0, 0, 0, 0));
|
||||
updateHologramText();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateHologramText() {
|
||||
if (textDisplay == null || !textDisplay.isValid()) return;
|
||||
|
||||
double secondsLeft = ticksUntilSpawn / 20.0;
|
||||
String color = type == GeneratorType.DIAMOND ? "§b§l" : "§a§l";
|
||||
String name = type.getDisplayName().toUpperCase();
|
||||
|
||||
String text = color + name + " GENERATOR\n" +
|
||||
"§eSpawning in §c" + String.format("%.1f", secondsLeft) + "s\n" +
|
||||
"§fLevel " + upgradeLevel;
|
||||
|
||||
textDisplay.setText(text);
|
||||
}
|
||||
|
||||
public void tick() {
|
||||
// Handle Base Spawner (Iron and Gold)
|
||||
if (type == GeneratorType.IRON_GOLD) {
|
||||
ticksUntilSpawn--;
|
||||
if (ticksUntilSpawn <= 0) {
|
||||
spawnItem(Material.IRON_INGOT);
|
||||
|
||||
// Spawn Gold at 1/4 the rate (upgrade increases rate)
|
||||
if (Math.random() < (0.25 * upgradeLevel)) {
|
||||
spawnItem(Material.GOLD_INGOT);
|
||||
}
|
||||
|
||||
// Reset with upgrade level modifier (faster spawns)
|
||||
ticksUntilSpawn = Math.max(5, maxSpawnTicks - (upgradeLevel - 1) * 3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle Diamond / Emerald Spawners
|
||||
ticksUntilSpawn--;
|
||||
if (ticksUntilSpawn % 5 == 0) {
|
||||
updateHologramText();
|
||||
}
|
||||
|
||||
if (ticksUntilSpawn <= 0) {
|
||||
// Spawn resource item
|
||||
spawnItem(type.getMaterial());
|
||||
|
||||
// Sparkle effect
|
||||
if (location.getWorld() != null) {
|
||||
location.getWorld().spawnParticle(
|
||||
type == GeneratorType.DIAMOND ? Particle.GLOW : Particle.HAPPY_VILLAGER,
|
||||
location.clone().add(0.5, 0.5, 0.5), 15, 0.2, 0.2, 0.2, 0.05
|
||||
);
|
||||
|
||||
// Premium chime sound
|
||||
location.getWorld().playSound(
|
||||
location, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.5f, 1.2f
|
||||
);
|
||||
}
|
||||
|
||||
ticksUntilSpawn = maxSpawnTicks;
|
||||
updateHologramText();
|
||||
}
|
||||
}
|
||||
|
||||
private int getExistingItemCount(Material material) {
|
||||
if (location.getWorld() == null) return 0;
|
||||
int count = 0;
|
||||
double radius = 1.5;
|
||||
for (org.bukkit.entity.Entity entity : location.getWorld().getNearbyEntities(location.clone().add(0.5, 0.5, 0.5), radius, radius, radius)) {
|
||||
if (entity instanceof Item itemEntity) {
|
||||
ItemStack stack = itemEntity.getItemStack();
|
||||
if (stack.getType() == material) {
|
||||
count += stack.getAmount();
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private int getMaxLimit(Material material) {
|
||||
switch (material) {
|
||||
case EMERALD: return 4;
|
||||
case DIAMOND: return 8;
|
||||
case GOLD_INGOT: return 12;
|
||||
case IRON_INGOT: return 48;
|
||||
default: return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
||||
private void spawnItem(Material material) {
|
||||
if (location.getWorld() == null) return;
|
||||
|
||||
int limit = getMaxLimit(material);
|
||||
int currentCount = getExistingItemCount(material);
|
||||
if (currentCount >= limit) {
|
||||
return; // Cap reached, do not drop item
|
||||
}
|
||||
|
||||
double cx = Math.floor(location.getX()) + 0.5;
|
||||
double cy = location.getY() + 0.5;
|
||||
double cz = Math.floor(location.getZ()) + 0.5;
|
||||
Location spawnLoc = new Location(location.getWorld(), cx, cy, cz);
|
||||
Item item = location.getWorld().dropItem(spawnLoc, new ItemStack(material, 1));
|
||||
|
||||
// Zero out initial velocity so items drop cleanly on the spawner
|
||||
item.setVelocity(new Vector(0, 0, 0));
|
||||
|
||||
// Mark this item as spawned by a generator to prevent duplication when dropped by a player
|
||||
BedwarsPlugin plugin = BedwarsPlugin.getInstance();
|
||||
if (plugin != null) {
|
||||
org.bukkit.NamespacedKey key = new org.bukkit.NamespacedKey(plugin, "generator_spawned");
|
||||
item.getPersistentDataContainer().set(key, org.bukkit.persistence.PersistentDataType.BYTE, (byte) 1);
|
||||
}
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (textDisplay != null && textDisplay.isValid()) {
|
||||
textDisplay.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
public GeneratorType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getUpgradeLevel() {
|
||||
return upgradeLevel;
|
||||
}
|
||||
|
||||
public void setUpgradeLevel(int upgradeLevel) {
|
||||
this.upgradeLevel = upgradeLevel;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class GeneratorManager {
|
||||
|
||||
private final BedwarsPlugin plugin;
|
||||
private final List<Generator> activeGenerators = new ArrayList<>();
|
||||
|
||||
public GeneratorManager(BedwarsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads generators from the plugin config and activates them in the world.
|
||||
*/
|
||||
public void loadGenerators() {
|
||||
cleanup(); // Clean up existing first
|
||||
|
||||
String worldName = plugin.getConfig().getString("world-name", "bedwars");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) {
|
||||
plugin.getLogger().warning("Cannot load generators: World '" + worldName + "' is not loaded!");
|
||||
return;
|
||||
}
|
||||
|
||||
int ironRate = plugin.getConfig().getInt("rates.iron", 20) * 2;
|
||||
int goldRate = plugin.getConfig().getInt("rates.gold", 80) * 2;
|
||||
int diamondRate = plugin.getConfig().getInt("rates.diamond", 600) * 2;
|
||||
int emeraldRate = plugin.getConfig().getInt("rates.emerald", 1200) * 2;
|
||||
|
||||
// Load map-wide generators (Diamond & Emerald) from the list in config
|
||||
List<Map<?, ?>> generatorList = plugin.getConfig().getMapList("locations.generators");
|
||||
for (Map<?, ?> genMap : generatorList) {
|
||||
try {
|
||||
String typeStr = (String) genMap.get("type");
|
||||
double x = ((Number) genMap.get("x")).doubleValue();
|
||||
double y = ((Number) genMap.get("y")).doubleValue();
|
||||
double z = ((Number) genMap.get("z")).doubleValue();
|
||||
|
||||
GeneratorType type = GeneratorType.valueOf(typeStr.toUpperCase());
|
||||
Location loc = new Location(world, x, y, z);
|
||||
|
||||
int ticks = type == GeneratorType.DIAMOND ? diamondRate : emeraldRate;
|
||||
activeGenerators.add(new Generator(loc, type, ticks));
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe("Failed to parse generator: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// Load base generators for active teams
|
||||
ConfigurationSection teamsSec = plugin.getConfig().getConfigurationSection("locations.teams");
|
||||
if (teamsSec != null) {
|
||||
for (String key : teamsSec.getKeys(false)) {
|
||||
ConfigurationSection teamSec = teamsSec.getConfigurationSection(key);
|
||||
if (teamSec != null && teamSec.getBoolean("enabled", false)) {
|
||||
if (teamSec.contains("generator")) {
|
||||
try {
|
||||
double x = teamSec.getDouble("generator.x");
|
||||
double y = teamSec.getDouble("generator.y");
|
||||
double z = teamSec.getDouble("generator.z");
|
||||
Location loc = new Location(world, x, y, z);
|
||||
|
||||
// Base generator produces Iron and Gold
|
||||
activeGenerators.add(new Generator(loc, GeneratorType.IRON_GOLD, ironRate));
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().severe("Failed to load base generator for team " + key + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugin.getLogger().info("Loaded " + activeGenerators.size() + " Bedwars resource generators!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ticks all active generators. Should be run every tick.
|
||||
*/
|
||||
public void tick() {
|
||||
for (Generator gen : activeGenerators) {
|
||||
gen.tick();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrades base generator rates for a specific team.
|
||||
*/
|
||||
public void upgradeTeamGenerator(BedwarsTeam team, int level) {
|
||||
String worldName = plugin.getConfig().getString("world-name", "bedwars");
|
||||
World world = Bukkit.getWorld(worldName);
|
||||
if (world == null) return;
|
||||
|
||||
double targetX = plugin.getConfig().getDouble("locations.teams." + team.getName().toLowerCase() + ".generator.x");
|
||||
double targetY = plugin.getConfig().getDouble("locations.teams." + team.getName().toLowerCase() + ".generator.y");
|
||||
double targetZ = plugin.getConfig().getDouble("locations.teams." + team.getName().toLowerCase() + ".generator.z");
|
||||
|
||||
for (Generator gen : activeGenerators) {
|
||||
if (gen.getType() == GeneratorType.IRON_GOLD) {
|
||||
Location loc = gen.getLocation();
|
||||
if (loc.getWorld() != null && loc.getWorld().equals(world) &&
|
||||
Math.abs(loc.getX() - targetX) < 1.0 &&
|
||||
Math.abs(loc.getY() - targetY) < 1.0 &&
|
||||
Math.abs(loc.getZ() - targetZ) < 1.0) {
|
||||
gen.setUpgradeLevel(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all active generators and deletes their hologram entities.
|
||||
*/
|
||||
public void cleanup() {
|
||||
for (Generator gen : activeGenerators) {
|
||||
gen.remove();
|
||||
}
|
||||
activeGenerators.clear();
|
||||
}
|
||||
|
||||
public List<Generator> getActiveGenerators() {
|
||||
return activeGenerators;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
|
||||
public enum GeneratorType {
|
||||
IRON_GOLD("Iron & Gold", ChatColor.GRAY, Material.IRON_INGOT),
|
||||
DIAMOND("Diamond", ChatColor.AQUA, Material.DIAMOND),
|
||||
EMERALD("Emerald", ChatColor.GREEN, Material.EMERALD);
|
||||
|
||||
private final String displayName;
|
||||
private final ChatColor color;
|
||||
private final Material material;
|
||||
|
||||
GeneratorType(String displayName, ChatColor color, Material material) {
|
||||
this.displayName = displayName;
|
||||
this.color = color;
|
||||
this.material = material;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public ChatColor getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public Material getMaterial() {
|
||||
return material;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package com.bedwars;
|
||||
|
||||
public enum LastDamageType {
|
||||
MELEE,
|
||||
PROJECTILE,
|
||||
FIREBALL,
|
||||
TNT,
|
||||
OTHER
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.scoreboard.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
public class ScoreboardManager {
|
||||
|
||||
private final BedwarsPlugin plugin;
|
||||
private final Map<UUID, Scoreboard> playerScoreboards = new HashMap<>();
|
||||
|
||||
public ScoreboardManager(BedwarsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void setupScoreboard(Player player) {
|
||||
org.bukkit.scoreboard.ScoreboardManager scoreboardManager = Bukkit.getScoreboardManager();
|
||||
if (scoreboardManager == null) return;
|
||||
|
||||
Scoreboard board = scoreboardManager.getNewScoreboard();
|
||||
Objective objective = board.registerNewObjective("bedwars", "dummy", "§e§lBEDWARS");
|
||||
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||
|
||||
player.setScoreboard(board);
|
||||
playerScoreboards.put(player.getUniqueId(), board);
|
||||
updateScoreboard(player);
|
||||
}
|
||||
|
||||
public void updateScoreboard(Player player) {
|
||||
Scoreboard board = playerScoreboards.get(player.getUniqueId());
|
||||
if (board == null) return;
|
||||
|
||||
GameManager gm = plugin.getGameManager();
|
||||
|
||||
// Register Bedwars teams and spectator team on this scoreboard for name tag and tab list colors
|
||||
for (BedwarsTeam t : BedwarsTeam.values()) {
|
||||
Team scoreTeam = board.getTeam(t.getName());
|
||||
if (scoreTeam == null) {
|
||||
scoreTeam = board.registerNewTeam(t.getName());
|
||||
}
|
||||
scoreTeam.setColor(t.getColor());
|
||||
scoreTeam.setPrefix(t.getColor().toString());
|
||||
scoreTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
|
||||
|
||||
// Clear existing entries to prevent stale data
|
||||
for (String entry : new java.util.ArrayList<>(scoreTeam.getEntries())) {
|
||||
scoreTeam.removeEntry(entry);
|
||||
}
|
||||
}
|
||||
|
||||
Team specTeam = board.getTeam("Spectators");
|
||||
if (specTeam == null) {
|
||||
specTeam = board.registerNewTeam("Spectators");
|
||||
}
|
||||
specTeam.setColor(ChatColor.GRAY);
|
||||
specTeam.setPrefix("§7");
|
||||
specTeam.setOption(Team.Option.COLLISION_RULE, Team.OptionStatus.NEVER);
|
||||
for (String entry : new java.util.ArrayList<>(specTeam.getEntries())) {
|
||||
specTeam.removeEntry(entry);
|
||||
}
|
||||
|
||||
// Add all online players to their respective teams on this scoreboard
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
if (gm.isSpectator(p)) {
|
||||
specTeam.addEntry(p.getName());
|
||||
} else {
|
||||
BedwarsTeam pTeam = gm.getPlayerTeam(p);
|
||||
if (pTeam != null) {
|
||||
Team scoreTeam = board.getTeam(pTeam.getName());
|
||||
if (scoreTeam != null) {
|
||||
scoreTeam.addEntry(p.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Objective objective = board.getObjective("bedwars");
|
||||
if (objective == null) return;
|
||||
|
||||
// Clear existing scores by unregistering and re-registering to ensure clean slate
|
||||
objective.unregister();
|
||||
objective = board.registerNewObjective("bedwars", "dummy", "§e§lBEDWARS");
|
||||
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||
|
||||
int line = 15;
|
||||
setLine(objective, "§7" + java.time.LocalDate.now().format(java.time.format.DateTimeFormatter.ofPattern("dd/MM/yy")), line--);
|
||||
setLine(objective, " ", line--);
|
||||
|
||||
GameState state = gm.getState();
|
||||
|
||||
if (state == GameState.LOBBY) {
|
||||
setLine(objective, "§fPlayers: §a" + Bukkit.getOnlinePlayers().size() + "§7/§a" + Bukkit.getMaxPlayers(), line--);
|
||||
setLine(objective, " ", line--);
|
||||
if (gm.isCountingDown()) {
|
||||
setLine(objective, "§fStarting in: §a" + gm.getCountdownTime() + "s", line--);
|
||||
} else {
|
||||
setLine(objective, "§fWaiting for players...", line--);
|
||||
}
|
||||
} else if (state == GameState.PLAYING) {
|
||||
setLine(objective, "§fMap: §a" + plugin.getConfig().getString("world-name", "bedwars"), line--);
|
||||
setLine(objective, " ", line--);
|
||||
|
||||
// Display team statuses
|
||||
for (BedwarsTeam team : BedwarsTeam.values()) {
|
||||
if (gm.isTeamEnabled(team)) {
|
||||
String status;
|
||||
if (gm.hasBed(team)) {
|
||||
status = "§a✔";
|
||||
} else {
|
||||
int alive = gm.getAliveTeamCount(team);
|
||||
if (alive > 0) {
|
||||
status = "§e" + alive;
|
||||
} else {
|
||||
status = "§c✘";
|
||||
}
|
||||
}
|
||||
setLine(objective, team.getColor() + team.getName().substring(0, 1) + " §f" + team.getName() + ": " + status, line--);
|
||||
}
|
||||
}
|
||||
|
||||
setLine(objective, " ", line--);
|
||||
setLine(objective, "§fKills: §a" + gm.getKills(player), line--);
|
||||
setLine(objective, "§fBeds Broken: §a" + gm.getBedsBroken(player), line--);
|
||||
} else if (state == GameState.ENDING) {
|
||||
setLine(objective, "§a§lGAME OVER!", line--);
|
||||
setLine(objective, " ", line--);
|
||||
BedwarsTeam winner = gm.getWinnerTeam();
|
||||
if (winner != null) {
|
||||
setLine(objective, "§fWinner: " + winner.getColorizedName(), line--);
|
||||
} else {
|
||||
setLine(objective, "§fWinner: §7None", line--);
|
||||
}
|
||||
}
|
||||
|
||||
setLine(objective, " ", line--);
|
||||
setLine(objective, "§dnexoria", line--);
|
||||
}
|
||||
|
||||
public void removeScoreboard(Player player) {
|
||||
playerScoreboards.remove(player.getUniqueId());
|
||||
player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
|
||||
}
|
||||
|
||||
public void updateAll() {
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
updateScoreboard(p);
|
||||
}
|
||||
}
|
||||
|
||||
private void setLine(Objective obj, String text, int scoreValue) {
|
||||
Score score = obj.getScore(text);
|
||||
score.setScore(scoreValue);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Villager;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.inventory.InventoryClickEvent;
|
||||
import org.bukkit.event.inventory.InventoryDragEvent;
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent;
|
||||
|
||||
public class ShopListener implements Listener {
|
||||
|
||||
private final BedwarsPlugin plugin;
|
||||
|
||||
public ShopListener(BedwarsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onPlayerInteractEntity(PlayerInteractEntityEvent event) {
|
||||
if (!(event.getRightClicked() instanceof Villager villager)) return;
|
||||
|
||||
String name = villager.getCustomName();
|
||||
if (name == null) return;
|
||||
|
||||
Player player = event.getPlayer();
|
||||
GameManager gm = plugin.getGameManager();
|
||||
|
||||
if (gm.getState() != GameState.PLAYING || gm.isSpectator(player)) {
|
||||
event.setCancelled(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (name.contains("ITEM SHOP")) {
|
||||
event.setCancelled(true);
|
||||
plugin.getShopManager().openShop(player, "blocks");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_YES, 0.8f, 1.2f);
|
||||
} else if (name.contains("TEAM UPGRADES")) {
|
||||
event.setCancelled(true);
|
||||
plugin.getUpgradesManager().openUpgradesGui(player);
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_YES, 0.8f, 1.2f);
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryClick(InventoryClickEvent event) {
|
||||
if (!(event.getWhoClicked() instanceof Player player)) return;
|
||||
|
||||
String title = event.getView().getTitle();
|
||||
|
||||
// 1. Handle Item Shop clicks
|
||||
if (title.startsWith("§8Item Shop - ")) {
|
||||
event.setCancelled(true);
|
||||
|
||||
// Make sure the click is inside the top inventory
|
||||
if (event.getClickedInventory() == null || event.getClickedInventory().equals(player.getInventory())) {
|
||||
return;
|
||||
}
|
||||
|
||||
int slot = event.getSlot();
|
||||
String currentCategory = title.replace("§8Item Shop - ", "").toLowerCase();
|
||||
|
||||
// Clicked Category Switcher (slots 1 to 7)
|
||||
if (slot >= 1 && slot <= 7) {
|
||||
String[] categories = {"blocks", "weapons", "armor", "tools", "bows", "potions", "utility"};
|
||||
String targetCat = categories[slot - 1];
|
||||
if (!targetCat.equalsIgnoreCase(currentCategory)) {
|
||||
plugin.getShopManager().openShop(player, targetCat);
|
||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 0.8f, 1.4f);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Clicked item purchase area (slots 18 to 44)
|
||||
if (slot >= 18 && slot <= 44) {
|
||||
// Ensure they didn't click border pane slots
|
||||
if (slot == 26 || slot == 27 || slot == 35 || slot == 36) return;
|
||||
|
||||
plugin.getShopManager().purchaseItem(player, currentCategory, slot);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Handle Upgrades GUI clicks
|
||||
if (title.equals("§8Team Upgrades")) {
|
||||
event.setCancelled(true);
|
||||
|
||||
if (event.getClickedInventory() == null || event.getClickedInventory().equals(player.getInventory())) {
|
||||
return;
|
||||
}
|
||||
|
||||
int slot = event.getSlot();
|
||||
if (slot >= 10 && slot <= 13) {
|
||||
plugin.getUpgradesManager().purchaseUpgrade(player, slot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onInventoryDrag(InventoryDragEvent event) {
|
||||
String title = event.getView().getTitle();
|
||||
if (title.startsWith("§8Item Shop - ") || title.equals("§8Team Upgrades")) {
|
||||
event.setCancelled(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,790 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.inventory.meta.PotionMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class ShopManager {
|
||||
|
||||
private final BedwarsPlugin plugin;
|
||||
|
||||
// Track tool and armor levels for players
|
||||
// 0 = None, 1 = Wood, 2 = Stone, 3 = Iron, 4 = Diamond
|
||||
private final Map<UUID, Integer> pickaxeLevels = new HashMap<>();
|
||||
private final Map<UUID, Integer> axeLevels = new HashMap<>();
|
||||
private final Set<UUID> hasShears = new HashSet<>();
|
||||
private final Map<UUID, Integer> armorLevels = new HashMap<>();
|
||||
|
||||
public ShopManager(BedwarsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void resetPlayerShopData(Player player) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
pickaxeLevels.remove(uuid);
|
||||
axeLevels.remove(uuid);
|
||||
hasShears.remove(uuid);
|
||||
armorLevels.remove(uuid);
|
||||
}
|
||||
|
||||
public void resetAllShopData() {
|
||||
pickaxeLevels.clear();
|
||||
axeLevels.clear();
|
||||
hasShears.clear();
|
||||
armorLevels.clear();
|
||||
}
|
||||
|
||||
public int getArmorTier(Player player) {
|
||||
return armorLevels.getOrDefault(player.getUniqueId(), 0);
|
||||
}
|
||||
|
||||
public void equipArmorTier(Player player, int tier) {
|
||||
Material legMat = Material.LEATHER_LEGGINGS;
|
||||
Material bootMat = Material.LEATHER_BOOTS;
|
||||
|
||||
if (tier == 1) {
|
||||
legMat = Material.CHAINMAIL_LEGGINGS;
|
||||
bootMat = Material.CHAINMAIL_BOOTS;
|
||||
} else if (tier == 2) {
|
||||
legMat = Material.IRON_LEGGINGS;
|
||||
bootMat = Material.IRON_BOOTS;
|
||||
} else if (tier == 3) {
|
||||
legMat = Material.DIAMOND_LEGGINGS;
|
||||
bootMat = Material.DIAMOND_BOOTS;
|
||||
}
|
||||
|
||||
ItemStack legs = new ItemStack(legMat);
|
||||
ItemStack boots = new ItemStack(bootMat);
|
||||
|
||||
ItemMeta m1 = legs.getItemMeta();
|
||||
ItemMeta m2 = boots.getItemMeta();
|
||||
if (m1 != null) { m1.setUnbreakable(true); legs.setItemMeta(m1); }
|
||||
if (m2 != null) { m2.setUnbreakable(true); boots.setItemMeta(m2); }
|
||||
|
||||
player.getInventory().setLeggings(legs);
|
||||
player.getInventory().setBoots(boots);
|
||||
|
||||
// Reapply team upgrades if present
|
||||
plugin.getUpgradesManager().applyTeamUpgrades(player);
|
||||
}
|
||||
|
||||
public void handlePlayerDeath(Player player) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
// Bedwars rule: keep shears (do not remove), and degrade pickaxe/axe by one tier (keep wooden tier 1)
|
||||
|
||||
if (pickaxeLevels.containsKey(uuid)) {
|
||||
int current = pickaxeLevels.get(uuid);
|
||||
if (current > 1) {
|
||||
pickaxeLevels.put(uuid, current - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (axeLevels.containsKey(uuid)) {
|
||||
int current = axeLevels.get(uuid);
|
||||
if (current > 1) {
|
||||
axeLevels.put(uuid, current - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasShears(Player player) {
|
||||
return hasShears.contains(player.getUniqueId());
|
||||
}
|
||||
|
||||
public int getPickaxeLevel(Player player) {
|
||||
return pickaxeLevels.getOrDefault(player.getUniqueId(), 0);
|
||||
}
|
||||
|
||||
public int getAxeLevel(Player player) {
|
||||
return axeLevels.getOrDefault(player.getUniqueId(), 0);
|
||||
}
|
||||
|
||||
public Material getPickaxeMaterial(int level) {
|
||||
switch (level) {
|
||||
case 1: return Material.WOODEN_PICKAXE;
|
||||
case 2: return Material.STONE_PICKAXE;
|
||||
case 3: return Material.IRON_PICKAXE;
|
||||
case 4: return Material.DIAMOND_PICKAXE;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Material getAxeMaterial(int level) {
|
||||
switch (level) {
|
||||
case 1: return Material.WOODEN_AXE;
|
||||
case 2: return Material.STONE_AXE;
|
||||
case 3: return Material.IRON_AXE;
|
||||
case 4: return Material.DIAMOND_AXE;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
public void giveTools(Player player) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
|
||||
// 1. Give shears if they have them
|
||||
if (hasShears.contains(uuid)) {
|
||||
ItemStack shears = new ItemStack(Material.SHEARS);
|
||||
ItemMeta m = shears.getItemMeta();
|
||||
if (m != null) {
|
||||
m.setUnbreakable(true);
|
||||
shears.setItemMeta(m);
|
||||
}
|
||||
player.getInventory().addItem(shears);
|
||||
}
|
||||
|
||||
// 2. Give pickaxe if they have it
|
||||
int pickLevel = pickaxeLevels.getOrDefault(uuid, 0);
|
||||
if (pickLevel > 0) {
|
||||
Material pickMat = getPickaxeMaterial(pickLevel);
|
||||
if (pickMat != null) {
|
||||
ItemStack pick = new ItemStack(pickMat);
|
||||
ItemMeta m = pick.getItemMeta();
|
||||
if (m != null) {
|
||||
m.setUnbreakable(true);
|
||||
pick.setItemMeta(m);
|
||||
}
|
||||
player.getInventory().addItem(pick);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Give axe if they have it
|
||||
int axeLevel = axeLevels.getOrDefault(uuid, 0);
|
||||
if (axeLevel > 0) {
|
||||
Material axeMat = getAxeMaterial(axeLevel);
|
||||
if (axeMat != null) {
|
||||
ItemStack axe = new ItemStack(axeMat);
|
||||
ItemMeta m = axe.getItemMeta();
|
||||
if (m != null) {
|
||||
m.setUnbreakable(true);
|
||||
axe.setItemMeta(m);
|
||||
}
|
||||
player.getInventory().addItem(axe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Bedwars Shop GUI for a player.
|
||||
*/
|
||||
public void openShop(Player player, String category) {
|
||||
Inventory inv = Bukkit.createInventory(null, 54, "§8Item Shop - " + capitalize(category));
|
||||
|
||||
// 1. Fill categories row (Row 0)
|
||||
setupCategories(inv, category);
|
||||
|
||||
// 2. Fill separator row (Row 1)
|
||||
for (int i = 9; i < 18; i++) {
|
||||
inv.setItem(i, createGuiItem(Material.BLACK_STAINED_GLASS_PANE, "§r", null));
|
||||
}
|
||||
|
||||
// 3. Load items from config for selected category
|
||||
List<String> itemsStr = plugin.getConfig().getStringList("shop." + category);
|
||||
int slot = 19; // Start listing in middle rows
|
||||
|
||||
for (String itemStr : itemsStr) {
|
||||
// Check if slot falls out of boundaries or enters right border
|
||||
if (slot == 26 || slot == 35 || slot == 44) slot += 2; // skip borders
|
||||
|
||||
try {
|
||||
ParsedShopItem shopItem = parseShopItem(itemStr, player);
|
||||
if (shopItem != null) {
|
||||
ItemStack displayStack = buildShopDisplayItem(shopItem, player);
|
||||
inv.setItem(slot++, displayStack);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
plugin.getLogger().warning("Failed to parse shop item line: " + itemStr + " - Error: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
private void setupCategories(Inventory inv, String activeCategory) {
|
||||
String[] categories = {"blocks", "weapons", "armor", "tools", "bows", "potions", "utility"};
|
||||
Material[] icons = {
|
||||
Material.RED_WOOL, Material.GOLDEN_SWORD, Material.CHAINMAIL_BOOTS,
|
||||
Material.STONE_PICKAXE, Material.BOW, Material.BREWING_STAND, Material.TNT
|
||||
};
|
||||
String[] names = {"§aBlocks", "§aWeapons", "§aArmor", "§aTools", "§aBows", "§aPotions", "§aUtility"};
|
||||
|
||||
for (int i = 0; i < categories.length; i++) {
|
||||
int slot = i + 1; // slots 1 to 7
|
||||
|
||||
ItemStack item = new ItemStack(icons[i]);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(names[i]);
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Click to open category");
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
inv.setItem(slot, item);
|
||||
}
|
||||
|
||||
// Left and right border padding for Row 0
|
||||
inv.setItem(0, createGuiItem(Material.GRAY_STAINED_GLASS_PANE, "§r", null));
|
||||
inv.setItem(8, createGuiItem(Material.GRAY_STAINED_GLASS_PANE, "§r", null));
|
||||
}
|
||||
|
||||
private ParsedShopItem parseShopItem(String raw, Player player) {
|
||||
String[] parts = raw.split(":");
|
||||
if (parts.length < 3) return null;
|
||||
|
||||
String matStr = parts[0];
|
||||
String costMatStr = parts[1];
|
||||
int costAmount = Integer.parseInt(parts[2]);
|
||||
String displayName = ChatColor.translateAlternateColorCodes('&', parts[3]);
|
||||
int amount = parts.length >= 5 ? Integer.parseInt(parts[4]) : 1;
|
||||
|
||||
// Resolve Wool color dynamically based on player's team
|
||||
Material material;
|
||||
if (matStr.equalsIgnoreCase("WOOL")) {
|
||||
BedwarsTeam team = plugin.getGameManager().getPlayerTeam(player);
|
||||
material = team != null ? team.getWoolMaterial() : Material.WHITE_WOOL;
|
||||
} else if (matStr.equalsIgnoreCase("BOW_POWER")) {
|
||||
material = Material.BOW;
|
||||
} else if (matStr.equalsIgnoreCase("KNOCKBACK_STICK")) {
|
||||
material = Material.STICK;
|
||||
} else if (matStr.equalsIgnoreCase("SPEED_POTION") || matStr.equalsIgnoreCase("INVISIBILITY_POTION") || matStr.equalsIgnoreCase("JUMP_POTION")) {
|
||||
material = Material.POTION;
|
||||
} else {
|
||||
material = Material.valueOf(matStr.toUpperCase());
|
||||
}
|
||||
|
||||
// Resolve Cost Material
|
||||
Material costMaterial;
|
||||
if (costMatStr.equalsIgnoreCase("IRON")) costMaterial = Material.IRON_INGOT;
|
||||
else if (costMatStr.equalsIgnoreCase("GOLD")) costMaterial = Material.GOLD_INGOT;
|
||||
else if (costMatStr.equalsIgnoreCase("DIAMOND")) costMaterial = Material.DIAMOND;
|
||||
else if (costMatStr.equalsIgnoreCase("EMERALD")) costMaterial = Material.EMERALD;
|
||||
else costMaterial = Material.valueOf(costMatStr.toUpperCase());
|
||||
|
||||
return new ParsedShopItem(raw, material, costMaterial, costAmount, displayName, amount);
|
||||
}
|
||||
|
||||
private ItemStack buildShopDisplayItem(ParsedShopItem item, Player player) {
|
||||
// Prevent buying weaker/equal armor visually
|
||||
if (item.material == Material.CHAINMAIL_BOOTS || item.material == Material.IRON_BOOTS || item.material == Material.DIAMOND_BOOTS) {
|
||||
int itemTier = 1;
|
||||
if (item.material == Material.IRON_BOOTS) itemTier = 2;
|
||||
else if (item.material == Material.DIAMOND_BOOTS) itemTier = 3;
|
||||
|
||||
int currentTier = getArmorTier(player);
|
||||
if (currentTier >= itemTier) {
|
||||
ItemStack stack = new ItemStack(item.material, item.amount);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(item.displayName);
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Amount: §b" + item.amount);
|
||||
lore.add("");
|
||||
lore.add("§a§lALREADY OWNED");
|
||||
meta.setLore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent buying weaker/equal swords visually
|
||||
if (item.material.name().contains("SWORD")) {
|
||||
int itemTier = getSwordTier(item.material);
|
||||
int currentBestTier = getBestSwordTier(player);
|
||||
if (currentBestTier >= itemTier) {
|
||||
ItemStack stack = new ItemStack(item.material, item.amount);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(item.displayName);
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Amount: §b" + item.amount);
|
||||
lore.add("");
|
||||
lore.add("§a§lALREADY OWNED");
|
||||
meta.setLore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent buying shears visually if already owned
|
||||
if (item.material == Material.SHEARS && hasShears(player)) {
|
||||
ItemStack stack = new ItemStack(item.material, item.amount);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(item.displayName);
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Amount: §b" + item.amount);
|
||||
lore.add("");
|
||||
lore.add("§a§lALREADY OWNED");
|
||||
meta.setLore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
// Prevent buying pickaxe visually if already maxed
|
||||
if (item.material == Material.WOODEN_PICKAXE && getPickaxeLevel(player) >= 4) {
|
||||
ItemStack stack = new ItemStack(Material.DIAMOND_PICKAXE, item.amount);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(item.displayName);
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Amount: §b" + item.amount);
|
||||
lore.add("");
|
||||
lore.add("§a§lMAXED OUT");
|
||||
meta.setLore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
// Prevent buying axe visually if already maxed
|
||||
if (item.material == Material.WOODEN_AXE && getAxeLevel(player) >= 4) {
|
||||
ItemStack stack = new ItemStack(Material.DIAMOND_AXE, item.amount);
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(item.displayName);
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Amount: §b" + item.amount);
|
||||
lore.add("");
|
||||
lore.add("§a§lMAXED OUT");
|
||||
meta.setLore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
ItemStack stack = new ItemStack(item.material, item.amount);
|
||||
|
||||
// Handle special modifications for tools, armor, potions, weapons
|
||||
applySpecialAttributes(stack, item, player);
|
||||
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(item.displayName);
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Amount: §b" + item.amount);
|
||||
lore.add("§7Cost: " + getCurrencyColor(item.costMaterial) + item.costAmount + " " + getCurrencyName(item.costMaterial));
|
||||
lore.add("");
|
||||
|
||||
boolean canAfford = hasEnoughResource(player, item.costMaterial, item.costAmount);
|
||||
if (canAfford) {
|
||||
lore.add("§e§lCLICK TO PURCHASE");
|
||||
} else {
|
||||
lore.add("§c§lYOU CANNOT AFFORD THIS");
|
||||
}
|
||||
meta.setLore(lore);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
private void applySpecialAttributes(ItemStack stack, ParsedShopItem item, Player player) {
|
||||
ItemMeta meta = stack.getItemMeta();
|
||||
if (meta == null) return;
|
||||
|
||||
// 1. Knockback Stick
|
||||
if (item.rawString.contains("KNOCKBACK_STICK")) {
|
||||
stack.setType(Material.STICK);
|
||||
meta.addEnchant(Enchantment.KNOCKBACK, 1, true);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
|
||||
// 2. Bow with Power I
|
||||
if (item.rawString.contains("BOW_POWER")) {
|
||||
stack.setType(Material.BOW);
|
||||
meta.addEnchant(Enchantment.POWER, 1, true);
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
|
||||
// 3. Potions
|
||||
if (item.material == Material.POTION || item.material == Material.SPLASH_POTION) {
|
||||
PotionMeta potMeta = (PotionMeta) meta;
|
||||
if (item.rawString.contains("SPEED_POTION")) {
|
||||
potMeta.addCustomEffect(new PotionEffect(PotionEffectType.SPEED, 900, 1), true); // Speed II for 45s
|
||||
} else if (item.rawString.contains("INVISIBILITY_POTION")) {
|
||||
potMeta.addCustomEffect(new PotionEffect(PotionEffectType.INVISIBILITY, 600, 0), true); // Invisibility for 30s
|
||||
} else if (item.rawString.contains("JUMP_POTION")) {
|
||||
potMeta.addCustomEffect(new PotionEffect(PotionEffectType.JUMP_BOOST, 900, 4), true); // Jump V for 45s
|
||||
}
|
||||
stack.setItemMeta(potMeta);
|
||||
}
|
||||
|
||||
// 4. Tools Progression
|
||||
if (item.material == Material.WOODEN_PICKAXE) {
|
||||
int currentLevel = pickaxeLevels.getOrDefault(player.getUniqueId(), 0);
|
||||
int nextLevel = Math.min(4, currentLevel + 1);
|
||||
|
||||
Material nextMat = Material.WOODEN_PICKAXE;
|
||||
String toolName = "§7Wooden Pickaxe";
|
||||
if (nextLevel == 2) { nextMat = Material.STONE_PICKAXE; toolName = "§7Stone Pickaxe"; }
|
||||
else if (nextLevel == 3) { nextMat = Material.IRON_PICKAXE; toolName = "§fIron Pickaxe"; }
|
||||
else if (nextLevel == 4) { nextMat = Material.DIAMOND_PICKAXE; toolName = "§bDiamond Pickaxe"; }
|
||||
|
||||
stack.setType(nextMat);
|
||||
item.material = nextMat;
|
||||
item.displayName = toolName + " §e(Tier " + nextLevel + ")";
|
||||
}
|
||||
|
||||
if (item.material == Material.WOODEN_AXE) {
|
||||
int currentLevel = axeLevels.getOrDefault(player.getUniqueId(), 0);
|
||||
int nextLevel = Math.min(4, currentLevel + 1);
|
||||
|
||||
Material nextMat = Material.WOODEN_AXE;
|
||||
String toolName = "§7Wooden Axe";
|
||||
if (nextLevel == 2) { nextMat = Material.STONE_AXE; toolName = "§7Stone Axe"; }
|
||||
else if (nextLevel == 3) { nextMat = Material.IRON_AXE; toolName = "§fIron Axe"; }
|
||||
else if (nextLevel == 4) { nextMat = Material.DIAMOND_AXE; toolName = "§bDiamond Axe"; }
|
||||
|
||||
stack.setType(nextMat);
|
||||
item.material = nextMat;
|
||||
item.displayName = toolName + " §e(Tier " + nextLevel + ")";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the purchase of a shop item.
|
||||
*/
|
||||
public void purchaseItem(Player player, String category, int slot) {
|
||||
List<String> itemsStr = plugin.getConfig().getStringList("shop." + category);
|
||||
|
||||
// Match slot back to config indices
|
||||
int expectedIndex = 0;
|
||||
int currentSlot = 19;
|
||||
boolean found = false;
|
||||
|
||||
for (String ignored : itemsStr) {
|
||||
if (currentSlot == 26 || currentSlot == 35 || currentSlot == 44) currentSlot += 2;
|
||||
if (currentSlot == slot) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
currentSlot++;
|
||||
expectedIndex++;
|
||||
}
|
||||
|
||||
if (!found || expectedIndex >= itemsStr.size()) return;
|
||||
|
||||
String itemStr = itemsStr.get(expectedIndex);
|
||||
ParsedShopItem shopItem = parseShopItem(itemStr, player);
|
||||
if (shopItem == null) return;
|
||||
|
||||
// Prevent buying weaker/equal armor
|
||||
if (shopItem.material == Material.CHAINMAIL_BOOTS || shopItem.material == Material.IRON_BOOTS || shopItem.material == Material.DIAMOND_BOOTS) {
|
||||
int itemTier = 1;
|
||||
if (shopItem.material == Material.IRON_BOOTS) itemTier = 2;
|
||||
else if (shopItem.material == Material.DIAMOND_BOOTS) itemTier = 3;
|
||||
|
||||
int currentTier = getArmorTier(player);
|
||||
if (currentTier >= itemTier) {
|
||||
player.sendMessage("§cYou already own equal or better armor!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent buying weaker/equal swords
|
||||
if (shopItem.material.name().contains("SWORD")) {
|
||||
int itemTier = getSwordTier(shopItem.material);
|
||||
int currentBestTier = getBestSwordTier(player);
|
||||
if (currentBestTier >= itemTier) {
|
||||
player.sendMessage("§cYou already own an equal or better sword!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent buying shears if already owned
|
||||
if (shopItem.material == Material.SHEARS && hasShears(player)) {
|
||||
player.sendMessage("§cYou already own shears!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent buying pickaxe if already maxed
|
||||
if (shopItem.material == Material.WOODEN_PICKAXE && getPickaxeLevel(player) >= 4) {
|
||||
player.sendMessage("§cYour Pickaxe is already maxed!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
// Prevent buying axe if already maxed
|
||||
if (shopItem.material == Material.WOODEN_AXE && getAxeLevel(player) >= 4) {
|
||||
player.sendMessage("§cYour Axe is already maxed!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
// Apply special modifications for display/upgrade levels
|
||||
ItemStack dummyStack = new ItemStack(shopItem.material);
|
||||
applySpecialAttributes(dummyStack, shopItem, player);
|
||||
|
||||
// Check if player has enough resource
|
||||
if (!hasEnoughResource(player, shopItem.costMaterial, shopItem.costAmount)) {
|
||||
player.sendMessage("§cYou cannot afford this item!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
// Deduct cost
|
||||
deductResource(player, shopItem.costMaterial, shopItem.costAmount);
|
||||
|
||||
// Deliver item
|
||||
deliverPurchase(player, shopItem);
|
||||
|
||||
// Refresh Shop
|
||||
openShop(player, category);
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_ITEM_PICKUP, 0.8f, 1.2f);
|
||||
}
|
||||
|
||||
private void deliverPurchase(Player player, ParsedShopItem shopItem) {
|
||||
UUID uuid = player.getUniqueId();
|
||||
Material mat = shopItem.material;
|
||||
|
||||
// 1. Shears
|
||||
if (mat == Material.SHEARS) {
|
||||
if (hasShears.contains(uuid)) {
|
||||
player.sendMessage("§cYou already have shears!");
|
||||
return;
|
||||
}
|
||||
hasShears.add(uuid);
|
||||
player.getInventory().addItem(new ItemStack(Material.SHEARS));
|
||||
player.sendMessage("§aPurchased Shears!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. Pickaxe Progression
|
||||
if (mat == Material.WOODEN_PICKAXE || mat == Material.STONE_PICKAXE ||
|
||||
mat == Material.IRON_PICKAXE || mat == Material.DIAMOND_PICKAXE) {
|
||||
int currentLevel = pickaxeLevels.getOrDefault(uuid, 0);
|
||||
int nextLevel = Math.min(4, currentLevel + 1);
|
||||
pickaxeLevels.put(uuid, nextLevel);
|
||||
|
||||
// Remove old pickaxes
|
||||
removeMaterials(player, Material.WOODEN_PICKAXE, Material.STONE_PICKAXE, Material.IRON_PICKAXE, Material.DIAMOND_PICKAXE);
|
||||
|
||||
ItemStack pick = new ItemStack(mat);
|
||||
ItemMeta m = pick.getItemMeta();
|
||||
if (m != null) {
|
||||
m.setUnbreakable(true);
|
||||
pick.setItemMeta(m);
|
||||
}
|
||||
|
||||
player.getInventory().addItem(pick);
|
||||
player.sendMessage("§aUpgraded Pickaxe to Tier " + nextLevel + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Axe Progression
|
||||
if (mat == Material.WOODEN_AXE || mat == Material.STONE_AXE ||
|
||||
mat == Material.IRON_AXE || mat == Material.DIAMOND_AXE) {
|
||||
int currentLevel = axeLevels.getOrDefault(uuid, 0);
|
||||
int nextLevel = Math.min(4, currentLevel + 1);
|
||||
axeLevels.put(uuid, nextLevel);
|
||||
|
||||
// Remove old axes
|
||||
removeMaterials(player, Material.WOODEN_AXE, Material.STONE_AXE, Material.IRON_AXE, Material.DIAMOND_AXE);
|
||||
|
||||
ItemStack axe = new ItemStack(mat);
|
||||
ItemMeta m = axe.getItemMeta();
|
||||
if (m != null) {
|
||||
m.setUnbreakable(true);
|
||||
axe.setItemMeta(m);
|
||||
}
|
||||
|
||||
player.getInventory().addItem(axe);
|
||||
player.sendMessage("§aUpgraded Axe to Tier " + nextLevel + "!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. Armor Upgrades (Chainmail, Iron, Diamond)
|
||||
if (mat == Material.CHAINMAIL_BOOTS || mat == Material.IRON_BOOTS || mat == Material.DIAMOND_BOOTS) {
|
||||
int targetTier = 1;
|
||||
if (mat == Material.IRON_BOOTS) targetTier = 2;
|
||||
else if (mat == Material.DIAMOND_BOOTS) targetTier = 3;
|
||||
|
||||
armorLevels.put(uuid, targetTier);
|
||||
equipArmorTier(player, targetTier);
|
||||
player.sendMessage("§aArmor upgraded successfully!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Swords replacing logic
|
||||
if (mat.name().contains("SWORD")) {
|
||||
handleSwordPurchase(player, mat, shopItem.displayName);
|
||||
return;
|
||||
}
|
||||
|
||||
// 5. Standard Item
|
||||
ItemStack purchasedStack = new ItemStack(mat, shopItem.amount);
|
||||
|
||||
// Reapply custom attributes (Knockback stick, bow, potions, etc.)
|
||||
applySpecialAttributes(purchasedStack, shopItem, player);
|
||||
|
||||
player.getInventory().addItem(purchasedStack);
|
||||
player.sendMessage("§aPurchased " + shopItem.displayName + "!");
|
||||
}
|
||||
|
||||
private void removeMaterials(Player player, Material... materials) {
|
||||
List<Material> list = Arrays.asList(materials);
|
||||
for (int i = 0; i < player.getInventory().getSize(); i++) {
|
||||
ItemStack item = player.getInventory().getItem(i);
|
||||
if (item != null && list.contains(item.getType())) {
|
||||
player.getInventory().setItem(i, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Checking currency counts
|
||||
public boolean hasEnoughResource(Player player, Material currency, int amount) {
|
||||
int count = 0;
|
||||
for (ItemStack item : player.getInventory().getContents()) {
|
||||
if (item != null && item.getType() == currency) {
|
||||
count += item.getAmount();
|
||||
}
|
||||
}
|
||||
return count >= amount;
|
||||
}
|
||||
|
||||
private void deductResource(Player player, Material currency, int amount) {
|
||||
int leftToDeduct = amount;
|
||||
ItemStack[] contents = player.getInventory().getContents();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
ItemStack item = contents[i];
|
||||
if (item != null && item.getType() == currency) {
|
||||
if (item.getAmount() > leftToDeduct) {
|
||||
item.setAmount(item.getAmount() - leftToDeduct);
|
||||
break;
|
||||
} else {
|
||||
leftToDeduct -= item.getAmount();
|
||||
player.getInventory().setItem(i, null);
|
||||
}
|
||||
}
|
||||
if (leftToDeduct <= 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
private String getCurrencyColor(Material material) {
|
||||
if (material == Material.IRON_INGOT) return "§f";
|
||||
if (material == Material.GOLD_INGOT) return "§6";
|
||||
if (material == Material.DIAMOND) return "§b";
|
||||
if (material == Material.EMERALD) return "§a";
|
||||
return "§7";
|
||||
}
|
||||
|
||||
private String getCurrencyName(Material material) {
|
||||
if (material == Material.IRON_INGOT) return "Iron";
|
||||
if (material == Material.GOLD_INGOT) return "Gold";
|
||||
if (material == Material.DIAMOND) return "Diamond";
|
||||
if (material == Material.EMERALD) return "Emerald";
|
||||
return material.name();
|
||||
}
|
||||
|
||||
private String capitalize(String text) {
|
||||
if (text == null || text.isEmpty()) return "";
|
||||
return text.substring(0, 1).toUpperCase() + text.substring(1).toLowerCase();
|
||||
}
|
||||
|
||||
private ItemStack createGuiItem(Material mat, String name, List<String> lore) {
|
||||
ItemStack item = new ItemStack(mat);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(name);
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
private int getBestSwordTier(Player player) {
|
||||
int bestTier = -1; // -1 means no sword
|
||||
for (ItemStack item : player.getInventory().getContents()) {
|
||||
if (item != null) {
|
||||
int tier = getSwordTier(item.getType());
|
||||
if (tier > bestTier) {
|
||||
bestTier = tier;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestTier;
|
||||
}
|
||||
|
||||
private int getSwordTier(Material material) {
|
||||
if (material == null) return -1;
|
||||
switch (material) {
|
||||
case WOODEN_SWORD: return 0;
|
||||
case STONE_SWORD: return 1;
|
||||
case IRON_SWORD: return 2;
|
||||
case DIAMOND_SWORD: return 3;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void handleSwordPurchase(Player player, Material newSwordMaterial, String displayName) {
|
||||
ItemStack[] contents = player.getInventory().getContents();
|
||||
int bestSwordSlot = -1;
|
||||
int bestSwordTier = -1;
|
||||
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
ItemStack item = contents[i];
|
||||
if (item != null) {
|
||||
int tier = getSwordTier(item.getType());
|
||||
if (tier > bestSwordTier) {
|
||||
bestSwordTier = tier;
|
||||
bestSwordSlot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemStack newSword = new ItemStack(newSwordMaterial);
|
||||
ItemMeta m = newSword.getItemMeta();
|
||||
if (m != null) {
|
||||
m.setUnbreakable(true);
|
||||
newSword.setItemMeta(m);
|
||||
}
|
||||
|
||||
if (bestSwordSlot != -1) {
|
||||
// Replace the old sword at its slot!
|
||||
player.getInventory().setItem(bestSwordSlot, newSword);
|
||||
player.sendMessage("§aUpgraded sword to " + displayName + "!");
|
||||
} else {
|
||||
// Otherwise, just add it to the inventory
|
||||
player.getInventory().addItem(newSword);
|
||||
player.sendMessage("§aPurchased " + displayName + "!");
|
||||
}
|
||||
|
||||
// Apply team upgrades (like sharpness!) to the new sword
|
||||
plugin.getUpgradesManager().applyTeamUpgrades(player);
|
||||
}
|
||||
|
||||
private static class ParsedShopItem {
|
||||
final String rawString;
|
||||
Material material;
|
||||
final Material costMaterial;
|
||||
final int costAmount;
|
||||
String displayName;
|
||||
final int amount;
|
||||
|
||||
ParsedShopItem(String rawString, Material material, Material costMaterial, int costAmount, String displayName, int amount) {
|
||||
this.rawString = rawString;
|
||||
this.material = material;
|
||||
this.costMaterial = costMaterial;
|
||||
this.costAmount = costAmount;
|
||||
this.displayName = displayName;
|
||||
this.amount = amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,254 @@
|
||||
package com.bedwars;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Sound;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
import org.bukkit.potion.PotionEffect;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class UpgradesManager {
|
||||
|
||||
private final BedwarsPlugin plugin;
|
||||
|
||||
// Upgrades maps per team
|
||||
private final Map<BedwarsTeam, Integer> sharpnessLevels = new HashMap<>();
|
||||
private final Map<BedwarsTeam, Integer> protectionLevels = new HashMap<>();
|
||||
private final Map<BedwarsTeam, Integer> hasteLevels = new HashMap<>();
|
||||
private final Map<BedwarsTeam, Integer> forgeLevels = new HashMap<>();
|
||||
|
||||
public UpgradesManager(BedwarsPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public void resetTeamUpgrades() {
|
||||
sharpnessLevels.clear();
|
||||
protectionLevels.clear();
|
||||
hasteLevels.clear();
|
||||
forgeLevels.clear();
|
||||
}
|
||||
|
||||
public int getSharpnessLevel(BedwarsTeam team) {
|
||||
return sharpnessLevels.getOrDefault(team, 0);
|
||||
}
|
||||
|
||||
public int getProtectionLevel(BedwarsTeam team) {
|
||||
return protectionLevels.getOrDefault(team, 0);
|
||||
}
|
||||
|
||||
public int getHasteLevel(BedwarsTeam team) {
|
||||
return hasteLevels.getOrDefault(team, 0);
|
||||
}
|
||||
|
||||
public int getForgeLevel(BedwarsTeam team) {
|
||||
return forgeLevels.getOrDefault(team, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the Team Upgrades GUI for a player.
|
||||
*/
|
||||
public void openUpgradesGui(Player player) {
|
||||
BedwarsTeam team = plugin.getGameManager().getPlayerTeam(player);
|
||||
if (team == null) return;
|
||||
|
||||
Inventory inv = Bukkit.createInventory(null, 27, "§8Team Upgrades");
|
||||
|
||||
// Padding
|
||||
for (int i = 0; i < 27; i++) {
|
||||
inv.setItem(i, createGuiItem(Material.BLACK_STAINED_GLASS_PANE, "§r", null));
|
||||
}
|
||||
|
||||
// 1. Sharpness (Slot 10)
|
||||
setupUpgradeIcon(inv, team, 10, Material.IRON_SWORD, "Sharpness", "§fPermanent Sharpness I on swords", "sharpness", getSharpnessLevel(team), 1);
|
||||
|
||||
// 2. Protection (Slot 11)
|
||||
setupUpgradeIcon(inv, team, 11, Material.IRON_CHESTPLATE, "Protection", "§fPermanent Protection on armor", "protection", getProtectionLevel(team), 4);
|
||||
|
||||
// 3. Haste (Slot 12)
|
||||
setupUpgradeIcon(inv, team, 12, Material.GOLDEN_PICKAXE, "Haste", "§fPermanent Haste effect", "haste", getHasteLevel(team), 2);
|
||||
|
||||
// 4. Forge (Slot 13)
|
||||
setupUpgradeIcon(inv, team, 13, Material.FURNACE, "Forge", "§fSpawns base resources faster", "forge", getForgeLevel(team), 4);
|
||||
|
||||
player.openInventory(inv);
|
||||
}
|
||||
|
||||
private void setupUpgradeIcon(Inventory inv, BedwarsTeam team, int slot, Material icon, String name, String benefit, String key, int currentLvl, int maxLvl) {
|
||||
ItemStack item = new ItemStack(icon);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName("§b§l" + name);
|
||||
List<String> lore = new ArrayList<>();
|
||||
lore.add("§7Benefit: " + benefit);
|
||||
lore.add("§7Current Level: §f" + (currentLvl == 0 ? "None" : "Tier " + currentLvl));
|
||||
lore.add("");
|
||||
|
||||
if (currentLvl >= maxLvl) {
|
||||
lore.add("§a§lMAX LEVEL REACHED");
|
||||
} else {
|
||||
int nextLvl = currentLvl + 1;
|
||||
int cost = plugin.getConfig().getIntegerList("upgrades." + key + ".cost").get(nextLvl - 1);
|
||||
String costMatName = plugin.getConfig().getString("upgrades." + key + ".material", "DIAMOND");
|
||||
|
||||
lore.add("§7Next Level: §aTier " + nextLvl);
|
||||
lore.add("§7Cost: §b" + cost + " " + costMatName);
|
||||
lore.add("");
|
||||
lore.add("§eClick to buy upgrade");
|
||||
}
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
inv.setItem(slot, item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles clicking an upgrade icon in the GUI.
|
||||
*/
|
||||
public void purchaseUpgrade(Player player, int slot) {
|
||||
BedwarsTeam team = plugin.getGameManager().getPlayerTeam(player);
|
||||
if (team == null) return;
|
||||
|
||||
String key = null;
|
||||
int maxLvl = 1;
|
||||
int currentLvl = 0;
|
||||
|
||||
if (slot == 10) { key = "sharpness"; maxLvl = 1; currentLvl = getSharpnessLevel(team); }
|
||||
else if (slot == 11) { key = "protection"; maxLvl = 4; currentLvl = getProtectionLevel(team); }
|
||||
else if (slot == 12) { key = "haste"; maxLvl = 2; currentLvl = getHasteLevel(team); }
|
||||
else if (slot == 13) { key = "forge"; maxLvl = 4; currentLvl = getForgeLevel(team); }
|
||||
|
||||
if (key == null) return;
|
||||
|
||||
if (currentLvl >= maxLvl) {
|
||||
player.sendMessage("§cYou have already maxed out this upgrade!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
int nextLvl = currentLvl + 1;
|
||||
int cost = plugin.getConfig().getIntegerList("upgrades." + key + ".cost").get(nextLvl - 1);
|
||||
String costMatStr = plugin.getConfig().getString("upgrades." + key + ".material", "DIAMOND");
|
||||
Material costMat = Material.valueOf(costMatStr.toUpperCase());
|
||||
|
||||
if (!plugin.getShopManager().hasEnoughResource(player, costMat, cost)) {
|
||||
player.sendMessage("§cYour team doesn't have enough Diamonds for this upgrade!");
|
||||
player.playSound(player.getLocation(), Sound.ENTITY_VILLAGER_NO, 1.0f, 1.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
// Deduct diamonds
|
||||
deductResource(player, costMat, cost);
|
||||
|
||||
// Apply levels
|
||||
if (key.equals("sharpness")) sharpnessLevels.put(team, nextLvl);
|
||||
else if (key.equals("protection")) protectionLevels.put(team, nextLvl);
|
||||
else if (key.equals("haste")) hasteLevels.put(team, nextLvl);
|
||||
else if (key.equals("forge")) {
|
||||
forgeLevels.put(team, nextLvl);
|
||||
// Upgrade spawner ticks
|
||||
plugin.getGeneratorManager().upgradeTeamGenerator(team, nextLvl);
|
||||
}
|
||||
|
||||
// Apply perks to team members instantly
|
||||
applyTeamUpgradesToAll(team);
|
||||
|
||||
// Notify team
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
if (plugin.getGameManager().getPlayerTeam(p) == team) {
|
||||
p.sendMessage("§a§lUPGRADE BOUGHT! §f" + player.getName() + " bought " + key.toUpperCase() + " Tier " + nextLvl + "!");
|
||||
p.playSound(p.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 0.8f, 1.2f);
|
||||
}
|
||||
}
|
||||
|
||||
// Reopen GUI
|
||||
openUpgradesGui(player);
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies upgrades to a specific team player (usually on spawn/respawn or when bought).
|
||||
*/
|
||||
public void applyTeamUpgrades(Player player) {
|
||||
BedwarsTeam team = plugin.getGameManager().getPlayerTeam(player);
|
||||
if (team == null) return;
|
||||
|
||||
// 1. Sharpness
|
||||
int sharpLvl = getSharpnessLevel(team);
|
||||
if (sharpLvl > 0) {
|
||||
for (ItemStack item : player.getInventory().getContents()) {
|
||||
if (item != null && item.getType().name().contains("SWORD")) {
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null && !meta.hasEnchant(Enchantment.SHARPNESS)) {
|
||||
meta.addEnchant(Enchantment.SHARPNESS, sharpLvl, true);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Protection
|
||||
int protLvl = getProtectionLevel(team);
|
||||
if (protLvl > 0) {
|
||||
for (ItemStack armor : player.getInventory().getArmorContents()) {
|
||||
if (armor != null && armor.getType() != Material.AIR) {
|
||||
ItemMeta meta = armor.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.addEnchant(Enchantment.PROTECTION, protLvl, true);
|
||||
armor.setItemMeta(meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Haste
|
||||
int hasteLvl = getHasteLevel(team);
|
||||
if (hasteLvl > 0) {
|
||||
// Remove old haste first
|
||||
player.removePotionEffect(PotionEffectType.HASTE);
|
||||
// Apply infinite haste effect
|
||||
player.addPotionEffect(new PotionEffect(PotionEffectType.HASTE, Integer.MAX_VALUE, hasteLvl - 1, true, false));
|
||||
}
|
||||
}
|
||||
|
||||
public void applyTeamUpgradesToAll(BedwarsTeam team) {
|
||||
for (Player p : Bukkit.getOnlinePlayers()) {
|
||||
if (plugin.getGameManager().getPlayerTeam(p) == team) {
|
||||
applyTeamUpgrades(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void deductResource(Player player, Material currency, int amount) {
|
||||
int leftToDeduct = amount;
|
||||
ItemStack[] contents = player.getInventory().getContents();
|
||||
for (int i = 0; i < contents.length; i++) {
|
||||
ItemStack item = contents[i];
|
||||
if (item != null && item.getType() == currency) {
|
||||
if (item.getAmount() > leftToDeduct) {
|
||||
item.setAmount(item.getAmount() - leftToDeduct);
|
||||
break;
|
||||
} else {
|
||||
leftToDeduct -= item.getAmount();
|
||||
player.getInventory().setItem(i, null);
|
||||
}
|
||||
}
|
||||
if (leftToDeduct <= 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
private ItemStack createGuiItem(Material mat, String name, List<String> lore) {
|
||||
ItemStack item = new ItemStack(mat);
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta != null) {
|
||||
meta.setDisplayName(name);
|
||||
meta.setLore(lore);
|
||||
item.setItemMeta(meta);
|
||||
}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user