Complete LoHub implementation: ETAP 4-10 (Custom Items, Launchpad, Double Jump, Player Hider, Scoreboard, Tablist, Announcements)
This commit is contained in:
parent
e78d8a2de4
commit
102341bb2c
12 changed files with 803 additions and 43 deletions
99
TODO.md
99
TODO.md
|
|
@ -20,7 +20,7 @@
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2. LoHub - Hub плагин (Paper/Folia)
|
### 2. LoHub - Hub плагин (Paper/Folia)
|
||||||
**Статус:** 🔄 В разработке (21% готово)
|
**Статус:** ✅ Готов к использованию (100% готово)
|
||||||
|
|
||||||
#### ✅ Готово
|
#### ✅ Готово
|
||||||
- ✅ Spawn система с телепортом
|
- ✅ Spawn система с телепортом
|
||||||
|
|
@ -28,49 +28,62 @@
|
||||||
- ✅ Защита мира (блоки, PvP, мобы)
|
- ✅ Защита мира (блоки, PvP, мобы)
|
||||||
- ✅ Команды /hub, /sethub, /lohub
|
- ✅ Команды /hub, /sethub, /lohub
|
||||||
- ✅ Базовые утилиты (ItemBuilder, TextUtil, PlaceholderUtil)
|
- ✅ Базовые утилиты (ItemBuilder, TextUtil, PlaceholderUtil)
|
||||||
|
- ✅ **ЭТАП 2: Action система**
|
||||||
|
- ✅ Action интерфейс и ActionType enum
|
||||||
|
- ✅ MessageAction, BroadcastAction, TitleAction, ActionbarAction
|
||||||
|
- ✅ SoundAction, CommandAction, ConsoleAction
|
||||||
|
- ✅ GamemodeAction, EffectAction, CloseAction
|
||||||
|
- ✅ ActionManager с regex парсингом
|
||||||
|
- ✅ **ЭТАП 3: Join система**
|
||||||
|
- ✅ PlayerJoinListener (join/quit/respawn/death)
|
||||||
|
- ✅ Телепорт на спавн при входе
|
||||||
|
- ✅ Хил и очистка эффектов
|
||||||
|
- ✅ Кастомные сообщения входа/выхода
|
||||||
|
- ✅ Фейерверки при первом входе
|
||||||
|
- ✅ Интеграция с Action системой
|
||||||
|
- ✅ **ЭТАП 4: Custom Join Items**
|
||||||
|
- ✅ HotbarManager - управление предметами
|
||||||
|
- ✅ Выдача предметов при входе
|
||||||
|
- ✅ HotbarListener - обработка кликов
|
||||||
|
- ✅ Защита от выбрасывания предметов
|
||||||
|
- ✅ Интеграция с Action системой
|
||||||
|
- ✅ **ЭТАП 5: Launchpad**
|
||||||
|
- ✅ LaunchpadListener - прыжковые площадки
|
||||||
|
- ✅ Проверка блоков (плита + редстоун)
|
||||||
|
- ✅ Настраиваемая сила прыжка
|
||||||
|
- ✅ Интеграция с Action системой
|
||||||
|
- ✅ **ЭТАП 6: Double Jump**
|
||||||
|
- ✅ DoubleJumpListener - двойной прыжок
|
||||||
|
- ✅ Интеграция с CooldownManager
|
||||||
|
- ✅ Настраиваемая сила и кулдаун
|
||||||
|
- ✅ Интеграция с Action системой
|
||||||
|
- ✅ **ЭТАП 7: Player Hider**
|
||||||
|
- ✅ PlayerHiderManager - управление видимостью
|
||||||
|
- ✅ Скрытие/показ игроков
|
||||||
|
- ✅ Предмет для переключения
|
||||||
|
- ✅ Кулдаун на использование
|
||||||
|
- ✅ **ЭТАП 8: Scoreboard**
|
||||||
|
- ✅ ScoreboardManager - управление скорбордом
|
||||||
|
- ✅ Настраиваемый заголовок и строки
|
||||||
|
- ✅ Автообновление с настраиваемым интервалом
|
||||||
|
- ✅ PlaceholderAPI интеграция
|
||||||
|
- ✅ **ЭТАП 9: Tablist**
|
||||||
|
- ✅ TablistManager - управление табом
|
||||||
|
- ✅ Настраиваемый header и footer
|
||||||
|
- ✅ Автообновление с настраиваемым интервалом
|
||||||
|
- ✅ PlaceholderAPI интеграция
|
||||||
|
- ✅ **ЭТАП 10: Announcements**
|
||||||
|
- ✅ AnnouncementManager - система объявлений
|
||||||
|
- ✅ Множественные объявления с ротацией
|
||||||
|
- ✅ Настраиваемый интервал и звук
|
||||||
|
- ✅ Минимальное количество игроков
|
||||||
|
- ✅ PlaceholderAPI интеграция
|
||||||
|
|
||||||
#### 🔄 В работе - ЭТАП 2: Action система
|
#### 📋 Дополнительно
|
||||||
- [ ] Action интерфейс и ActionType enum
|
- Все основные функции реализованы
|
||||||
- [ ] MessageAction - отправка сообщений
|
- Конфигурация полностью настраиваема через config.yml
|
||||||
- [ ] SoundAction - звуки
|
- Поддержка PlaceholderAPI для всех текстовых элементов
|
||||||
- [ ] TitleAction - title/subtitle
|
- Команда /lohub reload для перезагрузки конфигурации
|
||||||
- [ ] CommandAction - команды от игрока
|
|
||||||
- [ ] ConsoleAction - команды от консоли
|
|
||||||
- [ ] GamemodeAction - смена режима
|
|
||||||
- [ ] EffectAction - эффекты
|
|
||||||
- [ ] ActionManager - парсинг и выполнение
|
|
||||||
|
|
||||||
#### 📋 Запланировано
|
|
||||||
**ЭТАП 3: Join система**
|
|
||||||
- [ ] PlayerJoinListener
|
|
||||||
- [ ] Телепорт на спавн при входе
|
|
||||||
- [ ] Хил и очистка эффектов
|
|
||||||
- [ ] Кастомные сообщения входа/выхода
|
|
||||||
- [ ] Интеграция с Action системой
|
|
||||||
|
|
||||||
**ЭТАП 4: Custom Join Items**
|
|
||||||
- [ ] HotbarManager
|
|
||||||
- [ ] Выдача предметов при входе
|
|
||||||
- [ ] Обработка кликов (actions)
|
|
||||||
- [ ] Защита от выбрасывания
|
|
||||||
|
|
||||||
**ЭТАП 5: Launchpad**
|
|
||||||
- [ ] LaunchpadListener
|
|
||||||
- [ ] Прыжковые площадки (плита + редстоун)
|
|
||||||
|
|
||||||
**ЭТАП 6: Double Jump**
|
|
||||||
- [ ] DoubleJumpListener
|
|
||||||
- [ ] CooldownManager
|
|
||||||
- [ ] Двойной прыжок в воздухе
|
|
||||||
|
|
||||||
**ЭТАП 7: Player Hider**
|
|
||||||
- [ ] PlayerHiderManager
|
|
||||||
- [ ] Скрытие/показ игроков
|
|
||||||
- [ ] Предмет для переключения
|
|
||||||
|
|
||||||
**ЭТАП 8-10: Опционально**
|
|
||||||
- [ ] Scoreboard модуль
|
|
||||||
- [ ] Tablist модуль
|
|
||||||
- [ ] Announcements модуль
|
- [ ] Announcements модуль
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,14 @@ import com.loki.lohub.config.ConfigManager;
|
||||||
import com.loki.lohub.listeners.HubProtectionListener;
|
import com.loki.lohub.listeners.HubProtectionListener;
|
||||||
import com.loki.lohub.listeners.PlayerJoinListener;
|
import com.loki.lohub.listeners.PlayerJoinListener;
|
||||||
import com.loki.lohub.managers.ActionManager;
|
import com.loki.lohub.managers.ActionManager;
|
||||||
|
import com.loki.lohub.managers.AnnouncementManager;
|
||||||
import com.loki.lohub.managers.CooldownManager;
|
import com.loki.lohub.managers.CooldownManager;
|
||||||
|
import com.loki.lohub.managers.HotbarManager;
|
||||||
|
import com.loki.lohub.managers.PlayerHiderManager;
|
||||||
import com.loki.lohub.managers.RegionManager;
|
import com.loki.lohub.managers.RegionManager;
|
||||||
|
import com.loki.lohub.managers.ScoreboardManager;
|
||||||
import com.loki.lohub.managers.SpawnManager;
|
import com.loki.lohub.managers.SpawnManager;
|
||||||
|
import com.loki.lohub.managers.TablistManager;
|
||||||
import com.loki.lohub.utils.PlaceholderUtil;
|
import com.loki.lohub.utils.PlaceholderUtil;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
|
@ -17,6 +22,11 @@ public class LoHub extends JavaPlugin {
|
||||||
private RegionManager regionManager;
|
private RegionManager regionManager;
|
||||||
private ActionManager actionManager;
|
private ActionManager actionManager;
|
||||||
private CooldownManager cooldownManager;
|
private CooldownManager cooldownManager;
|
||||||
|
private HotbarManager hotbarManager;
|
||||||
|
private PlayerHiderManager playerHiderManager;
|
||||||
|
private ScoreboardManager scoreboardManager;
|
||||||
|
private TablistManager tablistManager;
|
||||||
|
private AnnouncementManager announcementManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
|
|
@ -31,23 +41,38 @@ public class LoHub extends JavaPlugin {
|
||||||
this.regionManager = new RegionManager(this);
|
this.regionManager = new RegionManager(this);
|
||||||
this.actionManager = new ActionManager(this);
|
this.actionManager = new ActionManager(this);
|
||||||
this.cooldownManager = new CooldownManager();
|
this.cooldownManager = new CooldownManager();
|
||||||
|
this.hotbarManager = new HotbarManager(this);
|
||||||
|
this.playerHiderManager = new PlayerHiderManager(this);
|
||||||
|
this.scoreboardManager = new ScoreboardManager(this);
|
||||||
|
this.tablistManager = new TablistManager(this);
|
||||||
|
this.announcementManager = new AnnouncementManager(this);
|
||||||
|
|
||||||
registerListeners();
|
registerListeners();
|
||||||
registerCommands();
|
registerCommands();
|
||||||
|
|
||||||
regionManager.createHubRegion();
|
regionManager.createHubRegion();
|
||||||
|
|
||||||
|
scoreboardManager.start();
|
||||||
|
tablistManager.start();
|
||||||
|
announcementManager.start();
|
||||||
|
|
||||||
getLogger().info("LoHub successfully loaded!");
|
getLogger().info("LoHub successfully loaded!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
|
scoreboardManager.stop();
|
||||||
|
tablistManager.stop();
|
||||||
|
announcementManager.stop();
|
||||||
getLogger().info("LoHub disabled!");
|
getLogger().info("LoHub disabled!");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerListeners() {
|
private void registerListeners() {
|
||||||
getServer().getPluginManager().registerEvents(new HubProtectionListener(this), this);
|
getServer().getPluginManager().registerEvents(new HubProtectionListener(this), this);
|
||||||
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
|
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
|
||||||
|
getServer().getPluginManager().registerEvents(new com.loki.lohub.listeners.HotbarListener(this), this);
|
||||||
|
getServer().getPluginManager().registerEvents(new com.loki.lohub.listeners.LaunchpadListener(this), this);
|
||||||
|
getServer().getPluginManager().registerEvents(new com.loki.lohub.listeners.DoubleJumpListener(this), this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void registerCommands() {
|
private void registerCommands() {
|
||||||
|
|
@ -75,4 +100,24 @@ public class LoHub extends JavaPlugin {
|
||||||
public CooldownManager getCooldownManager() {
|
public CooldownManager getCooldownManager() {
|
||||||
return cooldownManager;
|
return cooldownManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HotbarManager getHotbarManager() {
|
||||||
|
return hotbarManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PlayerHiderManager getPlayerHiderManager() {
|
||||||
|
return playerHiderManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ScoreboardManager getScoreboardManager() {
|
||||||
|
return scoreboardManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TablistManager getTablistManager() {
|
||||||
|
return tablistManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnnouncementManager getAnnouncementManager() {
|
||||||
|
return announcementManager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,12 @@ public class LoHubCommand implements CommandExecutor {
|
||||||
|
|
||||||
if (args[0].equalsIgnoreCase("reload")) {
|
if (args[0].equalsIgnoreCase("reload")) {
|
||||||
plugin.getConfigManager().reload();
|
plugin.getConfigManager().reload();
|
||||||
|
plugin.getHotbarManager().reload();
|
||||||
|
plugin.getAnnouncementManager().reload();
|
||||||
|
plugin.getScoreboardManager().stop();
|
||||||
|
plugin.getTablistManager().stop();
|
||||||
|
plugin.getScoreboardManager().start();
|
||||||
|
plugin.getTablistManager().start();
|
||||||
sender.sendMessage(TextUtil.colorize("&aConfiguration reloaded!"));
|
sender.sendMessage(TextUtil.colorize("&aConfiguration reloaded!"));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
package com.loki.lohub.listeners;
|
||||||
|
|
||||||
|
import com.loki.lohub.LoHub;
|
||||||
|
import org.bukkit.GameMode;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
import org.bukkit.event.player.PlayerToggleFlightEvent;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class DoubleJumpListener implements Listener {
|
||||||
|
|
||||||
|
private final LoHub plugin;
|
||||||
|
|
||||||
|
public DoubleJumpListener(LoHub plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
if (!plugin.getConfig().getBoolean("double_jump.enabled", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!player.isOnGround() && !player.getAllowFlight()) {
|
||||||
|
player.setAllowFlight(true);
|
||||||
|
} else if (player.isOnGround() && player.getAllowFlight()) {
|
||||||
|
player.setAllowFlight(false);
|
||||||
|
player.setFlying(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerToggleFlight(PlayerToggleFlightEvent event) {
|
||||||
|
if (!plugin.getConfig().getBoolean("double_jump.enabled", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
|
||||||
|
if (player.getGameMode() == GameMode.CREATIVE || player.getGameMode() == GameMode.SPECTATOR) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getCooldownManager().hasCooldown("double_jump", player.getUniqueId())) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.setAllowFlight(false);
|
||||||
|
player.setFlying(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.setCancelled(true);
|
||||||
|
player.setAllowFlight(false);
|
||||||
|
player.setFlying(false);
|
||||||
|
|
||||||
|
double power = plugin.getConfig().getDouble("double_jump.launch_power", 1.0);
|
||||||
|
double powerY = plugin.getConfig().getDouble("double_jump.launch_power_y", 0.9);
|
||||||
|
|
||||||
|
Vector velocity = player.getLocation().getDirection().multiply(power);
|
||||||
|
velocity.setY(powerY);
|
||||||
|
player.setVelocity(velocity);
|
||||||
|
|
||||||
|
int cooldown = plugin.getConfig().getInt("double_jump.cooldown", 3);
|
||||||
|
plugin.getCooldownManager().setCooldown("double_jump", player.getUniqueId(), cooldown);
|
||||||
|
|
||||||
|
List<String> actions = plugin.getConfig().getStringList("double_jump.actions");
|
||||||
|
if (!actions.isEmpty()) {
|
||||||
|
plugin.getActionManager().executeActions(player, actions, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.loki.lohub.listeners;
|
||||||
|
|
||||||
|
import com.loki.lohub.LoHub;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.block.Action;
|
||||||
|
import org.bukkit.event.player.PlayerDropItemEvent;
|
||||||
|
import org.bukkit.event.player.PlayerInteractEvent;
|
||||||
|
|
||||||
|
public class HotbarListener implements Listener {
|
||||||
|
|
||||||
|
private final LoHub plugin;
|
||||||
|
|
||||||
|
public HotbarListener(LoHub plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerInteract(PlayerInteractEvent event) {
|
||||||
|
if (event.getAction() != Action.RIGHT_CLICK_AIR && event.getAction() != Action.RIGHT_CLICK_BLOCK) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
int slot = player.getInventory().getHeldItemSlot();
|
||||||
|
|
||||||
|
if (plugin.getPlayerHiderManager().isPlayerHiderSlot(slot)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
|
||||||
|
if (plugin.getCooldownManager().hasCooldown("player_hider", player.getUniqueId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cooldown = plugin.getConfig().getInt("player_hider.cooldown", 3);
|
||||||
|
plugin.getCooldownManager().setCooldown("player_hider", player.getUniqueId(), cooldown);
|
||||||
|
|
||||||
|
plugin.getPlayerHiderManager().toggle(player);
|
||||||
|
} else if (plugin.getHotbarManager().isHotbarItem(slot)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
plugin.getHotbarManager().handleClick(player, slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerDropItem(PlayerDropItemEvent event) {
|
||||||
|
if (!plugin.getConfig().getBoolean("custom_join_items.disable_inventory_movement", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
int slot = player.getInventory().getHeldItemSlot();
|
||||||
|
|
||||||
|
if (plugin.getHotbarManager().isHotbarItem(slot) || plugin.getPlayerHiderManager().isPlayerHiderSlot(slot)) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,68 @@
|
||||||
|
package com.loki.lohub.listeners;
|
||||||
|
|
||||||
|
import com.loki.lohub.LoHub;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.EventHandler;
|
||||||
|
import org.bukkit.event.Listener;
|
||||||
|
import org.bukkit.event.player.PlayerMoveEvent;
|
||||||
|
import org.bukkit.util.Vector;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class LaunchpadListener implements Listener {
|
||||||
|
|
||||||
|
private final LoHub plugin;
|
||||||
|
|
||||||
|
public LaunchpadListener(LoHub plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
@EventHandler
|
||||||
|
public void onPlayerMove(PlayerMoveEvent event) {
|
||||||
|
if (!plugin.getConfig().getBoolean("launchpad.enabled", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.getFrom().getBlockX() == event.getTo().getBlockX()
|
||||||
|
&& event.getFrom().getBlockY() == event.getTo().getBlockY()
|
||||||
|
&& event.getFrom().getBlockZ() == event.getTo().getBlockZ()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
Block block = player.getLocation().getBlock();
|
||||||
|
|
||||||
|
String topBlockStr = plugin.getConfig().getString("launchpad.top_block", "STONE_PRESSURE_PLATE");
|
||||||
|
String bottomBlockStr = plugin.getConfig().getString("launchpad.bottom_block", "REDSTONE_BLOCK");
|
||||||
|
|
||||||
|
Material topMaterial = Material.getMaterial(topBlockStr);
|
||||||
|
Material bottomMaterial = Material.getMaterial(bottomBlockStr);
|
||||||
|
|
||||||
|
if (topMaterial == null || bottomMaterial == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (block.getType() == topMaterial) {
|
||||||
|
Block below = block.getRelative(0, -1, 0);
|
||||||
|
if (below.getType() == bottomMaterial) {
|
||||||
|
launchPlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void launchPlayer(Player player) {
|
||||||
|
double power = plugin.getConfig().getDouble("launchpad.launch_power", 3.0);
|
||||||
|
double powerY = plugin.getConfig().getDouble("launchpad.launch_power_y", 1.0);
|
||||||
|
|
||||||
|
Vector velocity = player.getLocation().getDirection().multiply(power);
|
||||||
|
velocity.setY(powerY);
|
||||||
|
player.setVelocity(velocity);
|
||||||
|
|
||||||
|
List<String> actions = plugin.getConfig().getStringList("launchpad.actions");
|
||||||
|
if (!actions.isEmpty()) {
|
||||||
|
plugin.getActionManager().executeActions(player, actions, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -65,6 +65,9 @@ public class PlayerJoinListener implements Listener {
|
||||||
handleJoinSettings(player);
|
handleJoinSettings(player);
|
||||||
handleJoinEvents(player);
|
handleJoinEvents(player);
|
||||||
handleFirework(player);
|
handleFirework(player);
|
||||||
|
|
||||||
|
plugin.getScoreboardManager().setScoreboard(player, true);
|
||||||
|
plugin.getTablistManager().setTablist(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler(priority = EventPriority.HIGHEST)
|
@EventHandler(priority = EventPriority.HIGHEST)
|
||||||
|
|
@ -75,6 +78,9 @@ public class PlayerJoinListener implements Listener {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugin.getPlayerHiderManager().removePlayer(player);
|
||||||
|
plugin.getScoreboardManager().removePlayer(player);
|
||||||
|
|
||||||
if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) {
|
if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) {
|
||||||
String quitMessage = plugin.getConfig().getString("join_leave_messages.quit_message", "");
|
String quitMessage = plugin.getConfig().getString("join_leave_messages.quit_message", "");
|
||||||
if (quitMessage.isEmpty()) {
|
if (quitMessage.isEmpty()) {
|
||||||
|
|
@ -144,6 +150,9 @@ public class PlayerJoinListener implements Listener {
|
||||||
if (plugin.getConfig().getBoolean("join_settings.clear_inventory", false)) {
|
if (plugin.getConfig().getBoolean("join_settings.clear_inventory", false)) {
|
||||||
player.getInventory().clear();
|
player.getInventory().clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugin.getHotbarManager().giveItems(player);
|
||||||
|
plugin.getPlayerHiderManager().giveItem(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleJoinEvents(Player player) {
|
private void handleJoinEvents(Player player) {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,108 @@
|
||||||
|
package com.loki.lohub.managers;
|
||||||
|
|
||||||
|
import com.loki.lohub.LoHub;
|
||||||
|
import com.loki.lohub.utils.PlaceholderUtil;
|
||||||
|
import com.loki.lohub.utils.TextUtil;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Sound;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class AnnouncementManager {
|
||||||
|
|
||||||
|
private final LoHub plugin;
|
||||||
|
private final List<Announcement> announcements = new ArrayList<>();
|
||||||
|
private int currentIndex = 0;
|
||||||
|
private int taskId = -1;
|
||||||
|
|
||||||
|
public AnnouncementManager(LoHub plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
loadAnnouncements();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAnnouncements() {
|
||||||
|
announcements.clear();
|
||||||
|
ConfigurationSection section = plugin.getConfig().getConfigurationSection("announcements.announcements");
|
||||||
|
if (section == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String key : section.getKeys(false)) {
|
||||||
|
List<String> messages = section.getStringList(key);
|
||||||
|
if (!messages.isEmpty()) {
|
||||||
|
announcements.add(new Announcement(key, messages));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
if (!plugin.getConfig().getBoolean("announcements.enabled", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (announcements.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int delay = plugin.getConfig().getInt("announcements.delay", 60) * 20;
|
||||||
|
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, this::broadcast, delay, delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (taskId != -1) {
|
||||||
|
Bukkit.getScheduler().cancelTask(taskId);
|
||||||
|
taskId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void broadcast() {
|
||||||
|
int requiredPlayers = plugin.getConfig().getInt("announcements.required_players", 1);
|
||||||
|
if (Bukkit.getOnlinePlayers().size() < requiredPlayers) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (announcements.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Announcement announcement = announcements.get(currentIndex);
|
||||||
|
currentIndex = (currentIndex + 1) % announcements.size();
|
||||||
|
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
for (String message : announcement.messages()) {
|
||||||
|
String formatted = PlaceholderUtil.parse(message, player);
|
||||||
|
player.sendMessage(Component.text(TextUtil.colorize(formatted)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getConfig().getBoolean("announcements.sound.enabled", true)) {
|
||||||
|
playSound(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void playSound(Player player) {
|
||||||
|
String soundStr = plugin.getConfig().getString("announcements.sound.value", "BLOCK_NOTE_BLOCK_PLING");
|
||||||
|
float volume = (float) plugin.getConfig().getDouble("announcements.sound.volume", 1.0);
|
||||||
|
float pitch = (float) plugin.getConfig().getDouble("announcements.sound.pitch", 1.0);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Sound sound = Sound.valueOf(soundStr);
|
||||||
|
player.playSound(player.getLocation(), sound, volume, pitch);
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
plugin.getLogger().warning("Invalid sound: " + soundStr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
stop();
|
||||||
|
loadAnnouncements();
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private record Announcement(String name, List<String> messages) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
package com.loki.lohub.managers;
|
||||||
|
|
||||||
|
import com.loki.lohub.LoHub;
|
||||||
|
import com.loki.lohub.utils.ItemBuilder;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.configuration.ConfigurationSection;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class HotbarManager {
|
||||||
|
|
||||||
|
private final LoHub plugin;
|
||||||
|
private final Map<Integer, HotbarItem> items = new HashMap<>();
|
||||||
|
|
||||||
|
public HotbarManager(LoHub plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
loadItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadItems() {
|
||||||
|
items.clear();
|
||||||
|
ConfigurationSection section = plugin.getConfig().getConfigurationSection("custom_join_items.items");
|
||||||
|
if (section == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (String key : section.getKeys(false)) {
|
||||||
|
ConfigurationSection itemSection = section.getConfigurationSection(key);
|
||||||
|
if (itemSection == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Material material = Material.getMaterial(itemSection.getString("material", "STONE"));
|
||||||
|
if (material == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slot = itemSection.getInt("slot", 0);
|
||||||
|
int amount = itemSection.getInt("amount", 1);
|
||||||
|
String displayName = itemSection.getString("display_name", "");
|
||||||
|
List<String> lore = itemSection.getStringList("lore");
|
||||||
|
List<String> actions = itemSection.getStringList("actions");
|
||||||
|
|
||||||
|
ItemStack item = new ItemBuilder(material)
|
||||||
|
.amount(amount)
|
||||||
|
.name(displayName)
|
||||||
|
.lore(lore)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
items.put(slot, new HotbarItem(item, actions));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void giveItems(Player player) {
|
||||||
|
if (!plugin.getConfig().getBoolean("custom_join_items.enabled", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, HotbarItem> entry : items.entrySet()) {
|
||||||
|
player.getInventory().setItem(entry.getKey(), entry.getValue().item());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void handleClick(Player player, int slot) {
|
||||||
|
HotbarItem item = items.get(slot);
|
||||||
|
if (item == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
plugin.getActionManager().executeActions(player, item.actions(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isHotbarItem(int slot) {
|
||||||
|
return items.containsKey(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
loadItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
private record HotbarItem(ItemStack item, List<String> actions) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package com.loki.lohub.managers;
|
||||||
|
|
||||||
|
import com.loki.lohub.LoHub;
|
||||||
|
import com.loki.lohub.utils.ItemBuilder;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class PlayerHiderManager {
|
||||||
|
|
||||||
|
private final LoHub plugin;
|
||||||
|
private final Set<UUID> hiddenPlayers = new HashSet<>();
|
||||||
|
|
||||||
|
public PlayerHiderManager(LoHub plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void giveItem(Player player) {
|
||||||
|
if (!plugin.getConfig().getBoolean("player_hider.enabled", true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int slot = plugin.getConfig().getInt("player_hider.slot", 8);
|
||||||
|
player.getInventory().setItem(slot, getItem(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ItemStack getItem(Player player) {
|
||||||
|
boolean hidden = hiddenPlayers.contains(player.getUniqueId());
|
||||||
|
String path = hidden ? "player_hider.hidden" : "player_hider.not_hidden";
|
||||||
|
|
||||||
|
Material material = Material.getMaterial(plugin.getConfig().getString(path + ".material", "LIME_DYE"));
|
||||||
|
if (material == null) {
|
||||||
|
material = Material.LIME_DYE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int amount = plugin.getConfig().getInt(path + ".amount", 1);
|
||||||
|
String displayName = plugin.getConfig().getString(path + ".display_name", "");
|
||||||
|
List<String> lore = plugin.getConfig().getStringList(path + ".lore");
|
||||||
|
|
||||||
|
return new ItemBuilder(material)
|
||||||
|
.amount(amount)
|
||||||
|
.name(displayName)
|
||||||
|
.lore(lore)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggle(Player player) {
|
||||||
|
if (hiddenPlayers.contains(player.getUniqueId())) {
|
||||||
|
showPlayers(player);
|
||||||
|
} else {
|
||||||
|
hidePlayers(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateItem(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void hidePlayers(Player player) {
|
||||||
|
hiddenPlayers.add(player.getUniqueId());
|
||||||
|
for (Player online : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (!online.equals(player)) {
|
||||||
|
player.hidePlayer(plugin, online);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showPlayers(Player player) {
|
||||||
|
hiddenPlayers.remove(player.getUniqueId());
|
||||||
|
for (Player online : Bukkit.getOnlinePlayers()) {
|
||||||
|
if (!online.equals(player)) {
|
||||||
|
player.showPlayer(plugin, online);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateItem(Player player) {
|
||||||
|
int slot = plugin.getConfig().getInt("player_hider.slot", 8);
|
||||||
|
player.getInventory().setItem(slot, getItem(player));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPlayerHiderSlot(int slot) {
|
||||||
|
return plugin.getConfig().getBoolean("player_hider.enabled", true)
|
||||||
|
&& slot == plugin.getConfig().getInt("player_hider.slot", 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePlayer(Player player) {
|
||||||
|
hiddenPlayers.remove(player.getUniqueId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,112 @@
|
||||||
|
package com.loki.lohub.managers;
|
||||||
|
|
||||||
|
import com.loki.lohub.LoHub;
|
||||||
|
import com.loki.lohub.utils.PlaceholderUtil;
|
||||||
|
import com.loki.lohub.utils.TextUtil;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.scoreboard.DisplaySlot;
|
||||||
|
import org.bukkit.scoreboard.Objective;
|
||||||
|
import org.bukkit.scoreboard.Scoreboard;
|
||||||
|
import org.bukkit.scoreboard.Team;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
public class ScoreboardManager {
|
||||||
|
|
||||||
|
private final LoHub plugin;
|
||||||
|
private final Map<UUID, Scoreboard> scoreboards = new HashMap<>();
|
||||||
|
private int taskId = -1;
|
||||||
|
|
||||||
|
public ScoreboardManager(LoHub plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
if (!plugin.getConfig().getBoolean("scoreboard.enabled", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getConfig().getBoolean("scoreboard.refresh.enabled", true)) {
|
||||||
|
int rate = plugin.getConfig().getInt("scoreboard.refresh.rate", 200);
|
||||||
|
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, this::updateAll, 0L, rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (taskId != -1) {
|
||||||
|
Bukkit.getScheduler().cancelTask(taskId);
|
||||||
|
taskId = -1;
|
||||||
|
}
|
||||||
|
scoreboards.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setScoreboard(Player player, boolean delayed) {
|
||||||
|
if (!plugin.getConfig().getBoolean("scoreboard.enabled", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delayed) {
|
||||||
|
int delay = plugin.getConfig().getInt("scoreboard.display_delay.server_enter", 60);
|
||||||
|
Bukkit.getScheduler().runTaskLater(plugin, () -> createScoreboard(player), delay);
|
||||||
|
} else {
|
||||||
|
createScoreboard(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createScoreboard(Player player) {
|
||||||
|
Scoreboard scoreboard = Bukkit.getScoreboardManager().getNewScoreboard();
|
||||||
|
Objective objective = scoreboard.registerNewObjective("lohub", "dummy", Component.text(""));
|
||||||
|
|
||||||
|
objective.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||||
|
updateScoreboard(player, scoreboard, objective);
|
||||||
|
|
||||||
|
player.setScoreboard(scoreboard);
|
||||||
|
scoreboards.put(player.getUniqueId(), scoreboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateScoreboard(Player player, Scoreboard scoreboard, Objective objective) {
|
||||||
|
String title = plugin.getConfig().getString("scoreboard.title", "");
|
||||||
|
title = PlaceholderUtil.parse(title, player);
|
||||||
|
objective.displayName(Component.text(TextUtil.colorize(title)));
|
||||||
|
|
||||||
|
List<String> lines = plugin.getConfig().getStringList("scoreboard.lines");
|
||||||
|
int score = lines.size();
|
||||||
|
|
||||||
|
for (String line : lines) {
|
||||||
|
line = PlaceholderUtil.parse(line, player);
|
||||||
|
line = TextUtil.colorize(line);
|
||||||
|
|
||||||
|
String teamName = "line_" + score;
|
||||||
|
Team team = scoreboard.getTeam(teamName);
|
||||||
|
if (team == null) {
|
||||||
|
team = scoreboard.registerNewTeam(teamName);
|
||||||
|
team.addEntry(teamName);
|
||||||
|
}
|
||||||
|
|
||||||
|
team.prefix(Component.text(line));
|
||||||
|
objective.getScore(teamName).setScore(score);
|
||||||
|
score--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAll() {
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
Scoreboard scoreboard = scoreboards.get(player.getUniqueId());
|
||||||
|
if (scoreboard != null) {
|
||||||
|
Objective objective = scoreboard.getObjective("lohub");
|
||||||
|
if (objective != null) {
|
||||||
|
updateScoreboard(player, scoreboard, objective);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removePlayer(Player player) {
|
||||||
|
scoreboards.remove(player.getUniqueId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,80 @@
|
||||||
|
package com.loki.lohub.managers;
|
||||||
|
|
||||||
|
import com.loki.lohub.LoHub;
|
||||||
|
import com.loki.lohub.utils.PlaceholderUtil;
|
||||||
|
import com.loki.lohub.utils.TextUtil;
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class TablistManager {
|
||||||
|
|
||||||
|
private final LoHub plugin;
|
||||||
|
private int taskId = -1;
|
||||||
|
|
||||||
|
public TablistManager(LoHub plugin) {
|
||||||
|
this.plugin = plugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
if (!plugin.getConfig().getBoolean("tablist.enabled", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (plugin.getConfig().getBoolean("tablist.refresh.enabled", true)) {
|
||||||
|
int rate = plugin.getConfig().getInt("tablist.refresh.rate", 400);
|
||||||
|
taskId = Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, this::updateAll, 0L, rate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void stop() {
|
||||||
|
if (taskId != -1) {
|
||||||
|
Bukkit.getScheduler().cancelTask(taskId);
|
||||||
|
taskId = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTablist(Player player) {
|
||||||
|
if (!plugin.getConfig().getBoolean("tablist.enabled", false)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTablist(player);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTablist(Player player) {
|
||||||
|
List<String> headerLines = plugin.getConfig().getStringList("tablist.header");
|
||||||
|
List<String> footerLines = plugin.getConfig().getStringList("tablist.footer");
|
||||||
|
|
||||||
|
StringBuilder header = new StringBuilder();
|
||||||
|
for (int i = 0; i < headerLines.size(); i++) {
|
||||||
|
String line = PlaceholderUtil.parse(headerLines.get(i), player);
|
||||||
|
header.append(TextUtil.colorize(line));
|
||||||
|
if (i < headerLines.size() - 1) {
|
||||||
|
header.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder footer = new StringBuilder();
|
||||||
|
for (int i = 0; i < footerLines.size(); i++) {
|
||||||
|
String line = PlaceholderUtil.parse(footerLines.get(i), player);
|
||||||
|
footer.append(TextUtil.colorize(line));
|
||||||
|
if (i < footerLines.size() - 1) {
|
||||||
|
footer.append("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
player.sendPlayerListHeaderAndFooter(
|
||||||
|
Component.text(header.toString()),
|
||||||
|
Component.text(footer.toString())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateAll() {
|
||||||
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
|
updateTablist(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue