diff --git a/src/main/java/de/fanta/challenges/challenges/DeathrunChallengeEvent.java b/src/main/java/de/fanta/challenges/challenges/DeathrunChallengeEvent.java index 1aba4a2..b1b8574 100644 --- a/src/main/java/de/fanta/challenges/challenges/DeathrunChallengeEvent.java +++ b/src/main/java/de/fanta/challenges/challenges/DeathrunChallengeEvent.java @@ -3,6 +3,7 @@ import de.fanta.challenges.Challenges; import de.fanta.challenges.events.TimerChangedEvent; import de.fanta.challenges.scoreboard.ChallengePlayer; +import de.fanta.challenges.scoreboard.Scorable; import de.fanta.challenges.scoreboard.ScoreManager; import de.fanta.challenges.utils.ChatSkullAPI.ChatSkull; import de.fanta.challenges.utils.ChatUtil; @@ -23,7 +24,6 @@ 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; @@ -57,13 +57,13 @@ scoreManager.setScore(new ChallengePlayer(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); + BossBar newBossBar = Bukkit.createBossBar(ChatUtil.GREEN + "Position: " + ChatUtil.BLUE + (scoreManager.getPosition(new ChallengePlayer(p))) + 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"); + bossBar.setTitle(ChatUtil.GREEN + "Position: " + ChatUtil.BLUE + (scoreManager.getPosition(new ChallengePlayer(p))) + ChatUtil.RED + " | " + ChatUtil.GREEN + " Distanz zum Spawn: " + ChatUtil.BLUE + distance + " Blöcke"); } @@ -138,18 +138,20 @@ public void onTimerChange(TimerChangedEvent e) { if (Objects.equals(plugin.getConfig().getString("event.type"), "deathrun")) { if (!e.isRunning()) { - Map.Entry maxEntry = null; //plugin.getScoreManager().getScores().entrySet().stream().max(Map.Entry.comparingByValue()).get(); //TODO: GANZ MACHEN - 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); + for (Scorable scorable : plugin.getScoreManager().getByPositon(1)) { + OfflinePlayer p = (Bukkit.getServer().getOfflinePlayer(scorable.getName())); + if (p.isOnline()) { + String[] lines = {"", "", "", " " + ChatUtil.BLUE + p.getName(), ChatUtil.GREEN + " ist " + plugin.getScoreManager().getScore(scorable) + " Blöcke gelaufen und", ChatUtil.GREEN + " hat damit gewonnen!", "", ""}; + ChatSkull.sendAll((Player) p, lines); + } else { + ChatUtil.sendBrodcastMessage(ChatUtil.BLUE + scorable.getName() + ChatUtil.GREEN + " ist " + plugin.getScoreManager().getScore(scorable) + " 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()) { + plugin.getScoreManager().join(new ChallengePlayer(pp)); Location spawn = world.getSpawnLocation(); spawn.setYaw(-90f); pp.teleport(spawn); diff --git a/src/main/java/de/fanta/challenges/listeners/QuitJoinListener.java b/src/main/java/de/fanta/challenges/listeners/QuitJoinListener.java index 8870396..64b4554 100644 --- a/src/main/java/de/fanta/challenges/listeners/QuitJoinListener.java +++ b/src/main/java/de/fanta/challenges/listeners/QuitJoinListener.java @@ -44,6 +44,7 @@ e.setJoinMessage(null); if (plugin.getServerType() != ServerType.ADVENTURE) { if (!DeathrunChallengeEvent.getDeadPlayer().contains(p.getUniqueId().toString())) { + plugin.getScoreManager().join(new ChallengePlayer(p)); plugin.getSBManager().setScoreboardtoPlayer(p); plugin.getSBManager().updateEventScoreboard(); if (!plugin.getConfig().getBoolean("event.teams") && plugin.getScoreManager().getScores() != null && plugin.getScoreManager().getScore(new ChallengePlayer(p)) == 0) { diff --git a/src/main/java/de/fanta/challenges/scoreboard/ChallengePlayer.java b/src/main/java/de/fanta/challenges/scoreboard/ChallengePlayer.java index ea4394e..66a4438 100644 --- a/src/main/java/de/fanta/challenges/scoreboard/ChallengePlayer.java +++ b/src/main/java/de/fanta/challenges/scoreboard/ChallengePlayer.java @@ -31,4 +31,9 @@ public String getIdentifier() { return player.getName(); } + + @Override + public String getName() { + return player.getName(); + } } diff --git a/src/main/java/de/fanta/challenges/scoreboard/Scorable.java b/src/main/java/de/fanta/challenges/scoreboard/Scorable.java index 9f4aba9..fb7ac2f 100644 --- a/src/main/java/de/fanta/challenges/scoreboard/Scorable.java +++ b/src/main/java/de/fanta/challenges/scoreboard/Scorable.java @@ -8,4 +8,6 @@ public abstract String getIdentifier(); + public abstract String getName(); + } diff --git a/src/main/java/de/fanta/challenges/scoreboard/ScoreManager.java b/src/main/java/de/fanta/challenges/scoreboard/ScoreManager.java index 0bfd55d..505c336 100644 --- a/src/main/java/de/fanta/challenges/scoreboard/ScoreManager.java +++ b/src/main/java/de/fanta/challenges/scoreboard/ScoreManager.java @@ -14,20 +14,23 @@ import javax.annotation.Nullable; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.IntPredicate; import java.util.logging.Level; import java.util.stream.Collectors; public class ScoreManager { - public class ScoreData { - private Scorable scorable; + public static class ScoreData { + private final Scorable scorable; private int score; private int position; private int index; @@ -85,6 +88,17 @@ this.positions = new ArrayList<>(); } + public void join(Scorable s) { + ScoreData data = new ScoreData(s, positions.size()); + scores.put(s, data); + positions.add(data); + } + + public void leave(Scorable s) { + ScoreData data = scores.remove(s); + positions.remove(data.getIndex()); + } + public void updateScore(Scorable s, int difference) { if (difference == 0) { return; @@ -96,37 +110,91 @@ int current = data.getIndex(); int dir = (int) Math.signum(difference * -1); - for (;current > 0 && positions.get(current + dir).getScore() < data.getScore(); current += dir) { - ScoreData predecessor = positions.get(current + dir); + IntPredicate forCondition = (dir == -1) ? curr -> curr > 0 && positions.get(curr - 1).getScore() < data.getScore() + : curr -> curr < positions.size() - 1 && positions.get(curr + 1).getScore() > data.getScore(); - positions.set(current + dir, data); - positions.set(current, predecessor); - data.setIndex(current + dir); - predecessor.setIndex(current); - data.setPosition(data.getPostition() + dir); - predecessor.setPosition(predecessor.getPostition() - dir); + // did we have the same score as the one before us and thus hat the same position but dont anymore because we got worse? + if (dir == 1 && current > 0 && data.getScore() == positions.get(current - 1).getScore()) { + data.setPosition(data.getPostition() + 1); } - if (current > 0 && data.getScore() == positions.get(current + dir).getScore()) { + // swap with neighbors as long as we are now better/worse then them + for (; forCondition.test(current); current += dir) { + ScoreData other = positions.get(current + dir); + + positions.set(current + dir, data); + positions.set(current, other); + data.setIndex(current + dir); + other.setIndex(current); + + int oldPosition = data.getPostition(); + data.setPosition(other.getPostition()); + other.setPosition(oldPosition); + } + + // do we now have the same score as the one before us and thus get the same position? + if (dir == -1 && current > 0 && data.getScore() == positions.get(current - 1).getScore()) { data.setPosition(positions.get(current + dir).getPostition()); } + // do the positions of those below us change as a result of our new position? + int lastPosition = data.getPostition(); + int lastScore = data.getScore(); + for (int i = current + 1; i < positions.size(); i++) { + ScoreData curr = positions.get(i); + int correctPosition = (curr.getScore() == lastScore) ? lastPosition : lastPosition + 1; + if (curr.getPostition() == correctPosition) + break; + + curr.setPosition(correctPosition); + lastPosition = correctPosition; + lastScore = curr.getScore(); + } + this.plugin.getSBManager().updateEventScore(s, difference); } public void setScore(Scorable s, int score) { - /*scores.put(s, score); - this.plugin.getSBManager().setEventScore(s, score);*/ + int diff = score - getScore(s); + updateScore(s, diff); } public int getScore(Scorable s) { return scores.get(s).getScore(); } - public int getPlayerPosition(Player player) { - List indexes = null; //scores.entrySet().stream().sorted(Map.Entry.comparingByValue((o1, o2) -> Integer.compare(o1, o2) * -1)).map(Map.Entry::getKey).toList(); //TODO: GANZ MACHEN - //return indexes.indexOf(player.getName()); - return 1; + public int getPosition(Scorable s) { + return scores.get(s).getPostition(); + } + + public Set getByPositon(int position) { + if (positions.isEmpty() || positions.get(positions.size() - 1).getPostition() < position) + return Collections.emptySet(); + + int start = position - 1; + int end = positions.size(); + + int found; + while (true) { + int middle = start + (end - start) / 2; + ScoreData current = positions.get(middle); + if (current.getPostition() == position) { + found = middle; + break; + } else if (current.getPostition() > position) { + end = middle; + } else { + start = middle; + } + } + + start = end = found; + for (; start > 0 && positions.get(start - 1).getPostition() == position; start--) { + } + for (; end < positions.size() - 2 && positions.get(end + 1).getPostition() == position; end++) { + } + + return positions.subList(start, end + 1).stream().map(ScoreData::getScorable).collect(Collectors.toSet()); } public void saveScores(@Nullable Player player) { @@ -163,22 +231,20 @@ sb.append(" Das Event hatte keine Teilnehmer!\n"); } else { if (plugin.getConfig().getBoolean("event.teams")) { - Set> sorted = null; //this.scores.entrySet().stream().sorted((o1, o2) -> o1.getValue().compareTo(o2.getValue()) * -1).collect(Collectors.toCollection(LinkedHashSet::new)); //TODO GANZ MACHEN int i = 1; - for (Map.Entry entry : sorted) { - ChallengeTeam challengeTeam = TeamUtils.getTeam(entry.getKey()); + for (ScoreData entry : positions) { + ChallengeTeam challengeTeam = TeamUtils.getTeam(entry.getScorable().getName()); if (challengeTeam != null) { Team team = TeamUtils.getScoreboard().getTeam(challengeTeam.getName()); if (team != null) { - sb.append(i++).append(". ").append(entry.getKey()).append(" (").append(team.getEntries().toString().replace("[", "").replace("]", "")).append(")").append(" ").append(entry.getValue()).append("\n"); + sb.append(i++).append(". ").append(entry.getScorable().getName()).append(" (").append(team.getEntries().toString().replace("[", "").replace("]", "")).append(")").append(" ").append(entry.getScore()).append("\n"); } } } } else { - Set> sorted = null; //this.scores.entrySet().stream().sorted((o1, o2) -> o1.getValue().compareTo(o2.getValue()) * -1).collect(Collectors.toCollection(LinkedHashSet::new)); //TODO GANZ MACHEN int i = 1; - for (Map.Entry entry : sorted) { - sb.append(i++).append(". ").append(entry.getKey()).append(" ").append(entry.getValue()).append("\n"); + for (ScoreData entry : positions) { + sb.append(i++).append(". ").append(entry.getScorable().getName()).append(" ").append(entry.getScore()).append("\n"); } } }