package de.fanta.challenges.challenges;
import de.fanta.challenges.Challenges;
import de.fanta.challenges.events.TimerChangedEvent;
import de.fanta.challenges.scoreboard.ScoreManager;
import de.fanta.challenges.utils.ChatSkullAPI.ChatSkull;
import de.fanta.challenges.utils.ChatUtil;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
import org.bukkit.GameRule;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.boss.BarColor;
import org.bukkit.boss.BarStyle;
import org.bukkit.boss.BossBar;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
public class DeathrunChallengeEvent implements Listener {
private final Challenges plugin = Challenges.getPlugin();
private static final List<String> deadPlayer = new ArrayList<>();
private final Map<Player, BossBar> bossBarMap = new HashMap<>();
public static Location spawnLocation;
private final Map<UUID, List<Location>> currentBarrier = new HashMap<>();
private static final Material barrierBlock = Material.GLASS;
@EventHandler
public void onMove(PlayerMoveEvent e) {
Player p = e.getPlayer();
World world = p.getWorld();
if (Objects.equals(plugin.getConfig().getString("event.type"), "deathrun") && plugin.getTimer().isRunning() && !plugin.getVanish().isVanish(p) && p.getGameMode() != GameMode.SPECTATOR) {
if (!deadPlayer.contains(p.getUniqueId().toString())) {
if (!e.getTo().equals(e.getFrom())) {
int distance = (int) p.getLocation().toVector().subtract(p.getWorld().getSpawnLocation().toVector()).length();
ScoreManager scoreManager = plugin.getScoreManager();
scoreManager.setScore(p, distance);
BossBar bossBar = bossBarMap.computeIfAbsent(p, player -> {
BossBar newBossBar = Bukkit.createBossBar(ChatUtil.GREEN + "Position: " + ChatUtil.BLUE + (scoreManager.getPlayerPosition(p) + 1) + ChatUtil.RED + " | " + ChatUtil.GREEN + " Distanz zum Spawn: " + ChatUtil.BLUE + distance + " Blöcke", BarColor.GREEN, BarStyle.SOLID);
newBossBar.setVisible(true);
newBossBar.addPlayer(p);
return newBossBar;
});
bossBar.setTitle(ChatUtil.GREEN + "Position: " + ChatUtil.BLUE + (scoreManager.getPlayerPosition(p) + 1) + ChatUtil.RED + " | " + ChatUtil.GREEN + " Distanz zum Spawn: " + ChatUtil.BLUE + distance + " Blöcke");
}
Location playerLoc = p.getLocation();
double posRelatedToCenter = playerLoc.getZ() - spawnLocation.getZ();
double distanceToCenter = Math.abs(posRelatedToCenter);
List<Location> barrierLocations = currentBarrier.computeIfAbsent(p.getUniqueId(), uuid -> new ArrayList<>());
int BARRIER_POS = 15;
int BARRIER_SIZE = 6;
if (distanceToCenter >= BARRIER_POS) { //Outside border
p.damage(0.5);
} else if (distanceToCenter >= BARRIER_POS - 4) { //Inside border
//Send barrier
double barrierZ = spawnLocation.getZ() + BARRIER_POS * (posRelatedToCenter > 0 ? 1 : -1);
Location loc = new Location(p.getWorld(), playerLoc.getX() - BARRIER_SIZE / 2d, playerLoc.getY() - BARRIER_SIZE / 2d, barrierZ);
resetBarrier(p, world, barrierLocations);
for (int y = 0; y < BARRIER_SIZE; y++) {
for (int x = 0; x < BARRIER_SIZE; x++) {
Location blockLoc = loc.clone().add(x, y, 0);
if (!world.getBlockAt(blockLoc).isSolid()) {
barrierLocations.add(blockLoc);
p.sendBlockChange(blockLoc, Bukkit.createBlockData(barrierBlock));
}
}
}
} else if (!barrierLocations.isEmpty()) { //Away from border
resetBarrier(p, world, barrierLocations);
}
if (playerLoc.getY() > world.getMaxHeight() - 1) {
p.damage(1);
}
}
}
}
@EventHandler
public void onDamage(EntityDamageEvent e) {
if (e.getEntity() instanceof Player p) {
if (Objects.equals(plugin.getConfig().getString("event.type"), "deathrun") && plugin.getTimer().isRunning()) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, () -> {
p.setWalkSpeed((float) (p.getHealth() / 100f));
}, 1L);
}
}
}
@EventHandler
public void onDeath(PlayerDeathEvent e) {
Player p = e.getEntity();
if (Objects.equals(plugin.getConfig().getString("event.type"), "deathrun") && plugin.getTimer().isRunning()) {
deadPlayer.add(p.getUniqueId().toString());
plugin.getSBManager().removeScoreboard(p);
if (plugin.getSBManager().countScoreboardPlayers() == 0) {
plugin.getTimer().stopTimer();
ChatUtil.sendBrodcastMessage("Das Event wurde beendet, da alle Spieler gestorben sind!");
}
}
}
@EventHandler
public void onPortalUse(PlayerPortalEvent e) {
if (Objects.equals(plugin.getConfig().getString("event.type"), "deathrun")) {
e.setCancelled(true);
}
}
@EventHandler
public void onTimerChange(TimerChangedEvent e) {
if (Objects.equals(plugin.getConfig().getString("event.type"), "deathrun")) {
if (!e.isRunning()) {
Map.Entry<String, Integer> maxEntry = plugin.getScoreManager().getScores().entrySet().stream().max(Map.Entry.comparingByValue()).get();
OfflinePlayer p = (Bukkit.getServer().getOfflinePlayer(maxEntry.getKey()));
if (p.isOnline()) {
String[] lines = {"", "", "", " " + ChatUtil.BLUE + p.getName(), ChatUtil.GREEN + " ist " + maxEntry.getValue() + " Blöcke gelaufen und", ChatUtil.GREEN + " hat damit gewonnen!", "", ""};
ChatSkull.sendAll((Player) p, lines);
} else {
ChatUtil.sendBrodcastMessage(ChatUtil.BLUE + maxEntry.getKey() + ChatUtil.GREEN + " ist " + maxEntry.getValue() + " Blöcke gelaufen und hat damit gewonnen!", ChatUtil.BLUE);
}
} else {
World world = Bukkit.getWorld("world");
world.setGameRule(GameRule.MAX_ENTITY_CRAMMING, Bukkit.getServer().getMaxPlayers());
for (Player pp : Bukkit.getOnlinePlayers()) {
Location spawn = world.getSpawnLocation();
spawn.setYaw(-90f);
pp.teleport(spawn);
}
}
}
}
@EventHandler
public void onBarrierBreak(BlockBreakEvent e) {
if (Objects.equals(plugin.getConfig().getString("event.type"), "deathrun")) {
Block block = e.getBlock();
Location loc = block.getLocation();
int x = loc.getBlockX();
int z = loc.getBlockZ();
int spawnX = spawnLocation.getBlockX();
int spawnZ = spawnLocation.getBlockZ();
int distanceX = spawnX - x;
if (distanceX > -15 && (Math.abs(distanceX) >= 15 || Math.abs(spawnZ - z) >= 15)) {
ChatUtil.sendWarningMessage(e.getPlayer(), "Niemand hat die Absicht, eine Mauer zu errichten!");
e.setCancelled(true);
}
}
}
public static void load() {
World world = Bukkit.getWorld("world");
spawnLocation = world.getSpawnLocation();
int height = world.getMaxHeight() - world.getMinHeight();
int width = 30;
Location loc = spawnLocation.clone().subtract(15, 0, 15);
loc.setY(world.getMinHeight());
for (int y = 0; y < height; y++) {
for (int z = 0; z < width; z++) {
Block block = loc.clone().add(0, y, z).getBlock();
if (!block.isSolid()) {
block.setType(barrierBlock);
}
}
}
mexico(15, world);
mexico(-15, world);
}
private void resetBarrier(Player p, World world, List<Location> locations) {
for (Location location : locations) {
p.sendBlockChange(location, world.getBlockAt(location).getBlockData());
}
locations.clear();
}
private static void mexico(int startPos, World world) {
int height = world.getMaxHeight() - world.getMinHeight();
int width = 30;
Location loc = spawnLocation.clone().add(-15, 0, startPos);
loc.setY(world.getMinHeight());
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
Block block = loc.clone().add(x, y, 0).getBlock();
if (!block.isSolid()) {
block.setType(barrierBlock);
}
}
}
}
public static List<String> getDeadPlayer() {
return deadPlayer;
}
}