Compare commits
No commits in common. "prod" and "1.2" have entirely different histories.
2
pom.xml
2
pom.xml
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
<groupId>ch.bensuisse</groupId>
|
<groupId>ch.bensuisse</groupId>
|
||||||
<artifactId>MiningMan</artifactId>
|
<artifactId>MiningMan</artifactId>
|
||||||
<version>2.0</version>
|
<version>1.2</version>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>MiningMan</name>
|
<name>MiningMan</name>
|
||||||
|
|||||||
@ -5,8 +5,6 @@ import ch.bensuisse.miningman.features.announce.AnnounceCommand;
|
|||||||
import ch.bensuisse.miningman.features.chat.ChatListener;
|
import ch.bensuisse.miningman.features.chat.ChatListener;
|
||||||
import ch.bensuisse.miningman.features.chat.ClearChatCommand;
|
import ch.bensuisse.miningman.features.chat.ClearChatCommand;
|
||||||
import ch.bensuisse.miningman.features.general.ConnectionListener;
|
import ch.bensuisse.miningman.features.general.ConnectionListener;
|
||||||
import ch.bensuisse.miningman.features.scoreboard.ScoreboardCommand;
|
|
||||||
import ch.bensuisse.miningman.features.scoreboard.ScoreboardService;
|
|
||||||
import ch.bensuisse.miningman.features.tablist.TablistService;
|
import ch.bensuisse.miningman.features.tablist.TablistService;
|
||||||
import ch.bensuisse.miningman.managers.JoinManager;
|
import ch.bensuisse.miningman.managers.JoinManager;
|
||||||
import net.luckperms.api.LuckPerms;
|
import net.luckperms.api.LuckPerms;
|
||||||
@ -18,7 +16,6 @@ public final class MiningMan extends JavaPlugin {
|
|||||||
|
|
||||||
private LuckPerms luckPerms;
|
private LuckPerms luckPerms;
|
||||||
private TablistService tablistService;
|
private TablistService tablistService;
|
||||||
private ScoreboardService scoreboardService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
@ -29,7 +26,6 @@ public final class MiningMan extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.tablistService = new TablistService(this, luckPerms);
|
this.tablistService = new TablistService(this, luckPerms);
|
||||||
this.scoreboardService = new ScoreboardService(this, luckPerms);
|
|
||||||
|
|
||||||
registerListeners();
|
registerListeners();
|
||||||
registerCommands();
|
registerCommands();
|
||||||
@ -42,8 +38,6 @@ public final class MiningMan extends JavaPlugin {
|
|||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
if (tablistService != null)
|
if (tablistService != null)
|
||||||
tablistService.onDisable();
|
tablistService.onDisable();
|
||||||
if (scoreboardService != null)
|
|
||||||
scoreboardService.onDisable();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean setupLuckPerms() {
|
private boolean setupLuckPerms() {
|
||||||
@ -61,7 +55,6 @@ public final class MiningMan extends JavaPlugin {
|
|||||||
pm.registerEvents(new ConnectionListener(luckPerms), this);
|
pm.registerEvents(new ConnectionListener(luckPerms), this);
|
||||||
pm.registerEvents(new ChatListener(this), this);
|
pm.registerEvents(new ChatListener(this), this);
|
||||||
pm.registerEvents(this.tablistService, this);
|
pm.registerEvents(this.tablistService, this);
|
||||||
pm.registerEvents(this.scoreboardService, this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerCommands() {
|
private void registerCommands() {
|
||||||
@ -78,17 +71,9 @@ public final class MiningMan extends JavaPlugin {
|
|||||||
ClearChatCommand clearChatCommand = new ClearChatCommand();
|
ClearChatCommand clearChatCommand = new ClearChatCommand();
|
||||||
getCommand("clearchat").setExecutor(clearChatCommand);
|
getCommand("clearchat").setExecutor(clearChatCommand);
|
||||||
getCommand("clearchat").setTabCompleter(clearChatCommand);
|
getCommand("clearchat").setTabCompleter(clearChatCommand);
|
||||||
|
|
||||||
ScoreboardCommand scoreboardCommand = new ScoreboardCommand(scoreboardService);
|
|
||||||
getCommand("sb").setExecutor(scoreboardCommand);
|
|
||||||
getCommand("sb").setTabCompleter(scoreboardCommand);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TablistService getTablistService() {
|
public TablistService getTablistService() {
|
||||||
return tablistService;
|
return tablistService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScoreboardService getScoreboardService() {
|
|
||||||
return scoreboardService;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import net.luckperms.api.LuckPerms;
|
|||||||
import net.luckperms.api.model.user.User;
|
import net.luckperms.api.model.user.User;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
import org.bukkit.event.EventHandler;
|
import org.bukkit.event.EventHandler;
|
||||||
import org.bukkit.event.EventPriority;
|
|
||||||
import org.bukkit.event.Listener;
|
import org.bukkit.event.Listener;
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
import org.bukkit.event.player.PlayerJoinEvent;
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
import org.bukkit.event.player.PlayerQuitEvent;
|
||||||
@ -18,14 +17,14 @@ public class ConnectionListener implements Listener {
|
|||||||
this.luckPerms = luckPerms;
|
this.luckPerms = luckPerms;
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler
|
||||||
public void onJoin(PlayerJoinEvent event) {
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
String prefix = getPrefix(event.getPlayer());
|
String prefix = getPrefix(event.getPlayer());
|
||||||
String msg = "<dark_gray>[<green>+<dark_gray>] <reset>" + prefix + " <white>" + event.getPlayer().getName();
|
String msg = "<dark_gray>[<green>+<dark_gray>] <reset>" + prefix + " <white>" + event.getPlayer().getName();
|
||||||
event.joinMessage(MiniMessage.miniMessage().deserialize(msg));
|
event.joinMessage(MiniMessage.miniMessage().deserialize(msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler
|
||||||
public void onQuit(PlayerQuitEvent event) {
|
public void onQuit(PlayerQuitEvent event) {
|
||||||
String prefix = getPrefix(event.getPlayer());
|
String prefix = getPrefix(event.getPlayer());
|
||||||
String msg = "<dark_gray>[<red>-<dark_gray>] <reset>" + prefix + " <white>" + event.getPlayer().getName();
|
String msg = "<dark_gray>[<red>-<dark_gray>] <reset>" + prefix + " <white>" + event.getPlayer().getName();
|
||||||
|
|||||||
@ -1,51 +0,0 @@
|
|||||||
package ch.bensuisse.miningman.features.scoreboard;
|
|
||||||
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
|
||||||
import org.bukkit.Sound;
|
|
||||||
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 org.jetbrains.annotations.NotNull;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public class ScoreboardCommand implements CommandExecutor, TabCompleter {
|
|
||||||
|
|
||||||
private static final TextColor THEME_COLOR = TextColor.fromHexString("#FFA80F");
|
|
||||||
|
|
||||||
private final ScoreboardService scoreboardService;
|
|
||||||
|
|
||||||
public ScoreboardCommand(ScoreboardService scoreboardService) {
|
|
||||||
this.scoreboardService = scoreboardService;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label,
|
|
||||||
@NotNull String[] args) {
|
|
||||||
if (!(sender instanceof Player player)) {
|
|
||||||
sender.sendMessage(Component.text("ᴏɴʟʏ ᴘʟᴀʏᴇʀs ᴄᴀɴ ᴜsᴇ ᴛʜɪs ᴄᴏᴍᴍᴀɴᴅ.", NamedTextColor.RED));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean enabled = scoreboardService.toggle(player);
|
|
||||||
String state = enabled ? "ᴇɴᴀʙʟᴇᴅ" : "ᴅɪsᴀʙʟᴇᴅ";
|
|
||||||
|
|
||||||
player.sendMessage(Component.text("➤ ", NamedTextColor.WHITE)
|
|
||||||
.append(Component.text("sᴄᴏʀᴇʙᴏᴀʀᴅ ", THEME_COLOR))
|
|
||||||
.append(Component.text(state, THEME_COLOR)));
|
|
||||||
player.playSound(player.getLocation(), Sound.UI_BUTTON_CLICK, 1.0f, enabled ? 1.2f : 0.8f);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<String> onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias,
|
|
||||||
@NotNull String[] args) {
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,337 +0,0 @@
|
|||||||
package ch.bensuisse.miningman.features.scoreboard;
|
|
||||||
|
|
||||||
import ch.bensuisse.miningman.MiningMan;
|
|
||||||
import ch.bensuisse.miningman.api.ColorUtil;
|
|
||||||
import io.papermc.paper.scoreboard.numbers.NumberFormat;
|
|
||||||
import net.kyori.adventure.text.Component;
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor;
|
|
||||||
import net.kyori.adventure.text.format.TextColor;
|
|
||||||
import net.kyori.adventure.text.format.TextDecoration;
|
|
||||||
import net.kyori.adventure.text.minimessage.MiniMessage;
|
|
||||||
import net.luckperms.api.LuckPerms;
|
|
||||||
import net.luckperms.api.model.user.User;
|
|
||||||
import org.bukkit.Bukkit;
|
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.Statistic;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.event.EventHandler;
|
|
||||||
import org.bukkit.event.Listener;
|
|
||||||
import org.bukkit.event.player.PlayerJoinEvent;
|
|
||||||
import org.bukkit.event.player.PlayerQuitEvent;
|
|
||||||
import org.bukkit.scoreboard.Criteria;
|
|
||||||
import org.bukkit.scoreboard.DisplaySlot;
|
|
||||||
import org.bukkit.scoreboard.Objective;
|
|
||||||
import org.bukkit.scoreboard.Scoreboard;
|
|
||||||
import org.bukkit.scoreboard.Team;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Persönliches Sidebar-Scoreboard: Name, Rang, Tode, Spielzeit, Online-Anzahl, platzierte/abgebaute
|
|
||||||
* Blöcke, gelaufene Blöcke sowie Server-IP. Standardmäßig für alle Spieler aktiv, kann pro Spieler
|
|
||||||
* mit /sb ein- oder ausgeblendet werden.
|
|
||||||
*/
|
|
||||||
public class ScoreboardService implements Listener {
|
|
||||||
|
|
||||||
private static final String OBJECTIVE_NAME = "miningman_sb";
|
|
||||||
private static final TextColor LABEL_COLOR = TextColor.fromHexString("#FE5A1D");
|
|
||||||
|
|
||||||
// Jede Zeile bekommt einen eigenen, satten Farbton - Titel und Icon in derselben Farbe.
|
|
||||||
private static final TextColor NAME_COLOR = TextColor.fromHexString("#FF5C8A");
|
|
||||||
private static final TextColor RANK_COLOR = TextColor.fromHexString("#FFD400");
|
|
||||||
private static final TextColor DEATHS_COLOR = TextColor.fromHexString("#FF3B3B");
|
|
||||||
private static final TextColor PLAYTIME_COLOR = TextColor.fromHexString("#FFA80F");
|
|
||||||
private static final TextColor ONLINE_COLOR = TextColor.fromHexString("#39FF6A");
|
|
||||||
private static final TextColor PLACED_COLOR = TextColor.fromHexString("#B14EFF");
|
|
||||||
private static final TextColor MINED_COLOR = TextColor.fromHexString("#C68642");
|
|
||||||
private static final TextColor WALKED_COLOR = TextColor.fromHexString("#22D3EE");
|
|
||||||
|
|
||||||
private static final String SEPARATOR = " "; // 25 Zeichen, als Leerzeichen für eine durchgehende Linie
|
|
||||||
private static final String SERVER_DOMAIN = "ᴍɪɴɪɴɢᴍᴀɴ.eu";
|
|
||||||
private static final List<Material> MINEABLE_MATERIALS = Arrays.stream(Material.values())
|
|
||||||
.filter(m -> m.isBlock() && !m.isLegacy())
|
|
||||||
.toList();
|
|
||||||
// USE_ITEM verlangt zwingend ein Material, das auch ein Item ist - reine Block-Varianten
|
|
||||||
// wie ACACIA_WALL_HANGING_SIGN (kein eigenes Item) fliegen sonst mit IllegalArgumentException raus.
|
|
||||||
private static final List<Material> PLACEABLE_MATERIALS = Arrays.stream(Material.values())
|
|
||||||
.filter(m -> m.isBlock() && m.isItem() && !m.isLegacy())
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
// Reihenfolge der Zeilen in buildLines(). Nur die dynamischen Indizes werden pro Update
|
|
||||||
// tatsächlich neu gesendet - Trennlinien, Leerzeilen und die IP-Zeile ändern sich nie.
|
|
||||||
private static final int LINE_COUNT = 13;
|
|
||||||
private static final int[] DYNAMIC_LINE_INDICES = { 1, 2, 4, 5, 6, 8, 9, 10 };
|
|
||||||
|
|
||||||
// Blöcke platziert/abgebaut erfordern eine Iteration über hunderte Materialien - das lohnt sich
|
|
||||||
// nicht bei jedem 2-Sekunden-Takt, deshalb wird nur alle paar Zyklen neu gerechnet und zwischengespeichert.
|
|
||||||
private static final int BLOCK_STATS_REFRESH_INTERVAL = 5; // ~10s bei 2s-Takt
|
|
||||||
|
|
||||||
private final MiningMan plugin;
|
|
||||||
private final LuckPerms luckPerms;
|
|
||||||
private final List<TextColor> gradientColors;
|
|
||||||
private final Set<UUID> disabled = new HashSet<>();
|
|
||||||
private final Map<UUID, PlayerBoard> boards = new HashMap<>();
|
|
||||||
private final Map<UUID, long[]> blockStatsCache = new HashMap<>();
|
|
||||||
private int tickCounter = 0;
|
|
||||||
|
|
||||||
public ScoreboardService(MiningMan plugin, LuckPerms luckPerms) {
|
|
||||||
this.plugin = plugin;
|
|
||||||
this.luckPerms = luckPerms;
|
|
||||||
this.gradientColors = ColorUtil.createGradient(TextColor.fromHexString("#FE5A1D"),
|
|
||||||
TextColor.fromHexString("#FFA80F"), 40);
|
|
||||||
|
|
||||||
Bukkit.getScheduler().runTaskTimer(plugin, this::updateAll, 20L, 40L);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onDisable() {
|
|
||||||
Scoreboard main = Bukkit.getScoreboardManager().getMainScoreboard();
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
||||||
player.setScoreboard(main);
|
|
||||||
}
|
|
||||||
boards.clear();
|
|
||||||
blockStatsCache.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onJoin(PlayerJoinEvent event) {
|
|
||||||
Bukkit.getScheduler().runTaskLater(plugin, () -> update(event.getPlayer(), true), 10L);
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
public void onQuit(PlayerQuitEvent event) {
|
|
||||||
UUID id = event.getPlayer().getUniqueId();
|
|
||||||
disabled.remove(id);
|
|
||||||
boards.remove(id);
|
|
||||||
blockStatsCache.remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Schaltet das Scoreboard für den Spieler um.
|
|
||||||
*
|
|
||||||
* @return true, wenn das Scoreboard danach aktiv ist, sonst false.
|
|
||||||
*/
|
|
||||||
public boolean toggle(Player player) {
|
|
||||||
UUID id = player.getUniqueId();
|
|
||||||
if (disabled.contains(id)) {
|
|
||||||
disabled.remove(id);
|
|
||||||
update(player, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
disabled.add(id);
|
|
||||||
boards.remove(id);
|
|
||||||
player.setScoreboard(Bukkit.getScoreboardManager().getMainScoreboard());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isEnabled(Player player) {
|
|
||||||
return !disabled.contains(player.getUniqueId());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateAll() {
|
|
||||||
boolean refreshBlockStats = (tickCounter++ % BLOCK_STATS_REFRESH_INTERVAL) == 0;
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
|
||||||
if (isEnabled(player))
|
|
||||||
update(player, refreshBlockStats);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void update(Player player, boolean refreshBlockStats) {
|
|
||||||
if (!isEnabled(player))
|
|
||||||
return;
|
|
||||||
|
|
||||||
boolean isNewBoard = !boards.containsKey(player.getUniqueId());
|
|
||||||
PlayerBoard board = boards.computeIfAbsent(player.getUniqueId(), id -> createBoard(player));
|
|
||||||
|
|
||||||
List<Component> lines = buildLines(player, refreshBlockStats || isNewBoard);
|
|
||||||
for (int index : DYNAMIC_LINE_INDICES) {
|
|
||||||
board.teams[index].prefix(lines.get(index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registriert Objective, Teams und Scores für einen Spieler genau einmal. Danach werden nur
|
|
||||||
* noch die Team-Prefixe der dynamischen Zeilen aktualisiert, statt das komplette Scoreboard
|
|
||||||
* jedes Mal neu aufzubauen und an den Client zu senden.
|
|
||||||
*/
|
|
||||||
private PlayerBoard createBoard(Player player) {
|
|
||||||
Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
|
|
||||||
Objective objective = scoreboard.registerNewObjective(OBJECTIVE_NAME, Criteria.DUMMY,
|
|
||||||
ColorUtil.applyGradient("MiningMan", gradientColors).decorate(TextDecoration.BOLD));
|
|
||||||
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
|
||||||
objective.numberFormat(NumberFormat.blank());
|
|
||||||
|
|
||||||
List<Component> lines = buildLines(player, true);
|
|
||||||
Team[] teams = new Team[LINE_COUNT];
|
|
||||||
|
|
||||||
int score = LINE_COUNT;
|
|
||||||
for (int i = 0; i < LINE_COUNT; i++) {
|
|
||||||
String entry = uniqueEntry(score);
|
|
||||||
Team team = scoreboard.registerNewTeam("l" + i);
|
|
||||||
team.addEntry(entry);
|
|
||||||
team.prefix(lines.get(i));
|
|
||||||
objective.getScore(entry).setScore(score);
|
|
||||||
teams[i] = team;
|
|
||||||
score--;
|
|
||||||
}
|
|
||||||
|
|
||||||
player.setScoreboard(scoreboard);
|
|
||||||
return new PlayerBoard(teams);
|
|
||||||
}
|
|
||||||
|
|
||||||
private List<Component> buildLines(Player player, boolean refreshBlockStats) {
|
|
||||||
long[] blockStats = getBlockStats(player, refreshBlockStats);
|
|
||||||
|
|
||||||
List<Component> lines = new ArrayList<>();
|
|
||||||
|
|
||||||
lines.add(separator());
|
|
||||||
lines.add(nameLine(player));
|
|
||||||
lines.add(rankLine(player));
|
|
||||||
lines.add(Component.empty());
|
|
||||||
lines.add(statLine("☠", DEATHS_COLOR, "ᴅᴇᴀᴛʜs",
|
|
||||||
String.valueOf(player.getStatistic(Statistic.DEATHS))));
|
|
||||||
lines.add(statLine("⌛", PLAYTIME_COLOR, "ᴘʟᴀʏᴛɪᴍᴇ",
|
|
||||||
formatPlaytime(player.getStatistic(Statistic.PLAY_ONE_MINUTE))));
|
|
||||||
lines.add(statLine("◎", ONLINE_COLOR, "ᴏɴʟɪɴᴇ",
|
|
||||||
Bukkit.getOnlinePlayers().size() + "/" + Bukkit.getMaxPlayers()));
|
|
||||||
lines.add(Component.empty());
|
|
||||||
lines.add(statLine("⧉", PLACED_COLOR, "ᴘʟᴀᴄᴇᴅ", formatNumber(blockStats[1])));
|
|
||||||
lines.add(statLine("⛏", MINED_COLOR, "ᴍɪɴᴇᴅ", formatNumber(blockStats[0])));
|
|
||||||
lines.add(statLine("⇄", WALKED_COLOR, "ᴡᴀʟᴋᴇᴅ", formatNumber(getBlocksWalked(player))));
|
|
||||||
lines.add(separator());
|
|
||||||
lines.add(ipLine());
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component separator() {
|
|
||||||
return ColorUtil.applyGradient(SEPARATOR, gradientColors).decorate(TextDecoration.STRIKETHROUGH);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component nameLine(Player player) {
|
|
||||||
return Component.text(" ✎ ", NAME_COLOR)
|
|
||||||
.append(Component.text("ɴᴀᴍᴇ: ", NAME_COLOR))
|
|
||||||
.append(Component.text(player.getName(), NamedTextColor.WHITE).decoration(TextDecoration.BOLD, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component rankLine(Player player) {
|
|
||||||
User user = luckPerms.getUserManager().getUser(player.getUniqueId());
|
|
||||||
String prefix = user != null ? user.getCachedData().getMetaData().getPrefix() : null;
|
|
||||||
|
|
||||||
Component rankValue;
|
|
||||||
if (prefix != null && !prefix.isEmpty()) {
|
|
||||||
rankValue = MiniMessage.miniMessage().deserialize(prefix);
|
|
||||||
} else {
|
|
||||||
rankValue = Component.text("-", NamedTextColor.WHITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Component.text(" ★ ", RANK_COLOR)
|
|
||||||
.append(Component.text("ʀᴀɴᴋ: ", RANK_COLOR))
|
|
||||||
.append(rankValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component statLine(String icon, TextColor color, String label, String value) {
|
|
||||||
return Component.text(" " + icon + " ", color)
|
|
||||||
.append(Component.text(label + ": ", color))
|
|
||||||
.append(Component.text(value, NamedTextColor.WHITE));
|
|
||||||
}
|
|
||||||
|
|
||||||
private Component ipLine() {
|
|
||||||
return Component.text(" → ", LABEL_COLOR)
|
|
||||||
.append(Component.text(SERVER_DOMAIN, NamedTextColor.WHITE))
|
|
||||||
.append(Component.text(" ← ", LABEL_COLOR));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Liefert {abgebaut, platziert} für einen Spieler. Wird nur bei refresh=true neu über alle
|
|
||||||
* Materialien berechnet, sonst kommt der zwischengespeicherte Wert vom letzten Refresh.
|
|
||||||
*/
|
|
||||||
private long[] getBlockStats(Player player, boolean refresh) {
|
|
||||||
UUID id = player.getUniqueId();
|
|
||||||
if (refresh || !blockStatsCache.containsKey(id)) {
|
|
||||||
long[] stats = { getBlocksMined(player), getBlocksPlaced(player) };
|
|
||||||
blockStatsCache.put(id, stats);
|
|
||||||
return stats;
|
|
||||||
}
|
|
||||||
return blockStatsCache.get(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Summiert die Bukkit-Statistik MINE_BLOCK über alle Blockarten (abgebaute Blöcke).
|
|
||||||
*/
|
|
||||||
private long getBlocksMined(Player player) {
|
|
||||||
long total = 0;
|
|
||||||
for (Material material : MINEABLE_MATERIALS) {
|
|
||||||
total += player.getStatistic(Statistic.MINE_BLOCK, material);
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Summiert die Bukkit-Statistik USE_ITEM über alle platzierbaren Blockarten. Bei platzierbaren
|
|
||||||
* Blöcken zählt "used" vanilla-seitig genau die Platzierungen (siehe Statistik-Screen im Spiel).
|
|
||||||
*/
|
|
||||||
private long getBlocksPlaced(Player player) {
|
|
||||||
long total = 0;
|
|
||||||
for (Material material : PLACEABLE_MATERIALS) {
|
|
||||||
total += player.getStatistic(Statistic.USE_ITEM, material);
|
|
||||||
}
|
|
||||||
return total;
|
|
||||||
}
|
|
||||||
|
|
||||||
private long getBlocksWalked(Player player) {
|
|
||||||
long cm = (long) player.getStatistic(Statistic.WALK_ONE_CM) + player.getStatistic(Statistic.SPRINT_ONE_CM);
|
|
||||||
return cm / 100L;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String formatPlaytime(int ticks) {
|
|
||||||
long minutes = ticks / 20L / 60L;
|
|
||||||
long days = minutes / 1440;
|
|
||||||
long hours = (minutes % 1440) / 60;
|
|
||||||
long mins = minutes % 60;
|
|
||||||
|
|
||||||
if (days > 0)
|
|
||||||
return days + "d " + hours + "h";
|
|
||||||
if (hours > 0)
|
|
||||||
return hours + "h " + mins + "m";
|
|
||||||
return mins + "m";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Zeigt Zahlen bis 9999 exakt an (z.B. 9640) und kürzt erst ab 10'000 auf "k" bzw.
|
|
||||||
* ab 1'000'000 auf "m" (z.B. 12k, 100k, 1m).
|
|
||||||
*/
|
|
||||||
private String formatNumber(long value) {
|
|
||||||
if (value < 10_000)
|
|
||||||
return String.valueOf(value);
|
|
||||||
if (value < 1_000_000)
|
|
||||||
return (value / 1000) + "k";
|
|
||||||
return (value / 1_000_000) + "m";
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Erzeugt eine unsichtbare, eindeutige Score-Entry aus Farbcodes (mehrere Zeilen ohne
|
|
||||||
* sichtbaren Text sind sonst nicht möglich, da jede Zeile im Scoreboard einen eigenen
|
|
||||||
* eindeutigen Eintrag benötigt).
|
|
||||||
*/
|
|
||||||
private String uniqueEntry(int index) {
|
|
||||||
StringBuilder sb = new StringBuilder();
|
|
||||||
int n = index + 1;
|
|
||||||
while (n > 0) {
|
|
||||||
sb.append(ChatColor.COLOR_CHAR).append(Integer.toHexString(n % 16));
|
|
||||||
n /= 16;
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private record PlayerBoard(Team[] teams) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -54,7 +54,6 @@ public class TablistService implements Listener {
|
|||||||
|
|
||||||
private void updateAll() {
|
private void updateAll() {
|
||||||
updateSorting();
|
updateSorting();
|
||||||
updatePlayerListNames();
|
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
updateHeaderFooter(player);
|
updateHeaderFooter(player);
|
||||||
}
|
}
|
||||||
@ -139,35 +138,6 @@ public class TablistService implements Listener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePlayerListNames() {
|
|
||||||
for (Player target : Bukkit.getOnlinePlayers()) {
|
|
||||||
User user = luckPerms.getUserManager().getUser(target.getUniqueId());
|
|
||||||
String prefix = user != null ? user.getCachedData().getMetaData().getPrefix() : null;
|
|
||||||
|
|
||||||
Component nameComponent = Component.text(target.getName(), NamedTextColor.WHITE)
|
|
||||||
.decoration(TextDecoration.BOLD, false);
|
|
||||||
if (prefix != null && !prefix.isEmpty()) {
|
|
||||||
Component rankComp = MiniMessage.miniMessage().deserialize(prefix);
|
|
||||||
nameComponent = rankComp.append(Component.text(" ").decoration(TextDecoration.BOLD, false))
|
|
||||||
.append(nameComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
target.playerListName(nameComponent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private TextColor getPingColor(int ping) {
|
|
||||||
if (ping <= 50) return NamedTextColor.GREEN;
|
|
||||||
if (ping <= 150) return NamedTextColor.YELLOW;
|
|
||||||
return NamedTextColor.RED;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TextColor getTpsColor(double tps) {
|
|
||||||
if (tps >= 18.0) return NamedTextColor.GREEN;
|
|
||||||
if (tps >= 15.0) return NamedTextColor.YELLOW;
|
|
||||||
return NamedTextColor.RED;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateHeaderFooter(Player player) {
|
private void updateHeaderFooter(Player player) {
|
||||||
Component title = ColorUtil.applyGradient("ᴍɪɴɪɴɢᴍᴀɴ.eu", gradientColors)
|
Component title = ColorUtil.applyGradient("ᴍɪɴɪɴɢᴍᴀɴ.eu", gradientColors)
|
||||||
.decorate(TextDecoration.BOLD);
|
.decorate(TextDecoration.BOLD);
|
||||||
@ -184,16 +154,8 @@ public class TablistService implements Listener {
|
|||||||
Component discordLine = Component.text(" ᴅɪsᴄᴏʀᴅ: ", TextColor.fromHexString("#FE5A1D"))
|
Component discordLine = Component.text(" ᴅɪsᴄᴏʀᴅ: ", TextColor.fromHexString("#FE5A1D"))
|
||||||
.append(Component.text("discord.gg/V32MCYsFhn ", NamedTextColor.WHITE));
|
.append(Component.text("discord.gg/V32MCYsFhn ", NamedTextColor.WHITE));
|
||||||
|
|
||||||
double tps = Math.min(20.0, Bukkit.getServer().getTPS()[0]);
|
|
||||||
Component tpsLine = Component.text(" ᴛᴘs: ", TextColor.fromHexString("#FE5A1D"))
|
|
||||||
.append(Component.text(String.format("%.1f", tps), getTpsColor(tps)))
|
|
||||||
.append(Component.text(" ᴘɪɴɢ: ", TextColor.fromHexString("#FE5A1D")))
|
|
||||||
.append(Component.text(player.getPing() + "ms", getPingColor(player.getPing())));
|
|
||||||
|
|
||||||
Component footer = Component.newline()
|
Component footer = Component.newline()
|
||||||
.append(discordLine)
|
.append(discordLine)
|
||||||
.append(Component.newline())
|
|
||||||
.append(tpsLine)
|
|
||||||
.append(Component.newline());
|
.append(Component.newline());
|
||||||
|
|
||||||
player.sendPlayerListHeaderAndFooter(header, footer);
|
player.sendPlayerListHeaderAndFooter(header, footer);
|
||||||
|
|||||||
@ -13,5 +13,6 @@ public class JoinManager implements Listener {
|
|||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
public void onJoin(PlayerJoinEvent event) {
|
public void onJoin(PlayerJoinEvent event) {
|
||||||
|
event.getPlayer().setLevel(2026);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
name: MiningMan
|
name: MiningMan
|
||||||
version: '2.0'
|
version: '1.2'
|
||||||
main: ch.bensuisse.miningman.MiningMan
|
main: ch.bensuisse.miningman.MiningMan
|
||||||
api-version: '1.21'
|
api-version: '1.21'
|
||||||
authors: [BenSuisse]
|
authors: [BenSuisse]
|
||||||
@ -18,5 +18,3 @@ commands:
|
|||||||
usage: /clearchat
|
usage: /clearchat
|
||||||
aliases: [cc]
|
aliases: [cc]
|
||||||
permission: miningman.clearchat
|
permission: miningman.clearchat
|
||||||
sb:
|
|
||||||
usage: /sb
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user