feat: LoHub Action system + Join system implementation

This commit is contained in:
loki5512344 2026-02-23 17:27:34 +01:00
parent 69cae99476
commit 6a4c8a7886
55 changed files with 3180 additions and 1022 deletions

View file

@ -0,0 +1,78 @@
package com.loki.lohub;
import com.loki.lohub.config.ConfigManager;
import com.loki.lohub.listeners.HubProtectionListener;
import com.loki.lohub.listeners.PlayerJoinListener;
import com.loki.lohub.managers.ActionManager;
import com.loki.lohub.managers.CooldownManager;
import com.loki.lohub.managers.RegionManager;
import com.loki.lohub.managers.SpawnManager;
import com.loki.lohub.utils.PlaceholderUtil;
import org.bukkit.plugin.java.JavaPlugin;
public class LoHub extends JavaPlugin {
private ConfigManager configManager;
private SpawnManager spawnManager;
private RegionManager regionManager;
private ActionManager actionManager;
private CooldownManager cooldownManager;
@Override
public void onEnable() {
getLogger().info("Loading LoHub v" + getDescription().getVersion());
saveDefaultConfig();
PlaceholderUtil.init();
this.configManager = new ConfigManager(this);
this.spawnManager = new SpawnManager(this);
this.regionManager = new RegionManager(this);
this.actionManager = new ActionManager(this);
this.cooldownManager = new CooldownManager();
registerListeners();
registerCommands();
regionManager.createHubRegion();
getLogger().info("LoHub successfully loaded!");
}
@Override
public void onDisable() {
getLogger().info("LoHub disabled!");
}
private void registerListeners() {
getServer().getPluginManager().registerEvents(new HubProtectionListener(this), this);
getServer().getPluginManager().registerEvents(new PlayerJoinListener(this), this);
}
private void registerCommands() {
getCommand("hub").setExecutor(new com.loki.lohub.commands.HubCommand(this));
getCommand("sethub").setExecutor(new com.loki.lohub.commands.SetHubCommand(this));
getCommand("lohub").setExecutor(new com.loki.lohub.commands.LoHubCommand(this));
}
public ConfigManager getConfigManager() {
return configManager;
}
public SpawnManager getSpawnManager() {
return spawnManager;
}
public RegionManager getRegionManager() {
return regionManager;
}
public ActionManager getActionManager() {
return actionManager;
}
public CooldownManager getCooldownManager() {
return cooldownManager;
}
}

View file

@ -0,0 +1,10 @@
package com.loki.lohub.actions;
import org.bukkit.entity.Player;
public interface Action {
void execute(Player player);
ActionType getType();
}

View file

@ -0,0 +1,23 @@
package com.loki.lohub.actions;
public enum ActionType {
MESSAGE,
BROADCAST,
TITLE,
ACTIONBAR,
SOUND,
COMMAND,
CONSOLE,
GAMEMODE,
EFFECT,
CLOSE,
UNKNOWN;
public static ActionType fromString(String type) {
try {
return valueOf(type.toUpperCase());
} catch (IllegalArgumentException e) {
return UNKNOWN;
}
}
}

View file

@ -0,0 +1,28 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import com.loki.lohub.utils.PlaceholderUtil;
import com.loki.lohub.utils.TextUtil;
import net.kyori.adventure.text.Component;
import org.bukkit.entity.Player;
public class ActionbarAction implements Action {
private final String message;
public ActionbarAction(String message) {
this.message = message;
}
@Override
public void execute(Player player) {
String parsed = PlaceholderUtil.parse(message, player);
player.sendActionBar(Component.text(TextUtil.colorize(parsed)));
}
@Override
public ActionType getType() {
return ActionType.ACTIONBAR;
}
}

View file

@ -0,0 +1,28 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import com.loki.lohub.utils.PlaceholderUtil;
import com.loki.lohub.utils.TextUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class BroadcastAction implements Action {
private final String message;
public BroadcastAction(String message) {
this.message = message;
}
@Override
public void execute(Player player) {
String parsed = PlaceholderUtil.parse(message, player);
Bukkit.broadcastMessage(TextUtil.colorize(parsed));
}
@Override
public ActionType getType() {
return ActionType.BROADCAST;
}
}

View file

@ -0,0 +1,18 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import org.bukkit.entity.Player;
public class CloseAction implements Action {
@Override
public void execute(Player player) {
player.closeInventory();
}
@Override
public ActionType getType() {
return ActionType.CLOSE;
}
}

View file

@ -0,0 +1,26 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import com.loki.lohub.utils.PlaceholderUtil;
import org.bukkit.entity.Player;
public class CommandAction implements Action {
private final String command;
public CommandAction(String command) {
this.command = command;
}
@Override
public void execute(Player player) {
String parsed = PlaceholderUtil.parse(command, player);
player.performCommand(parsed);
}
@Override
public ActionType getType() {
return ActionType.COMMAND;
}
}

View file

@ -0,0 +1,27 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import com.loki.lohub.utils.PlaceholderUtil;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public class ConsoleAction implements Action {
private final String command;
public ConsoleAction(String command) {
this.command = command;
}
@Override
public void execute(Player player) {
String parsed = PlaceholderUtil.parse(command, player);
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), parsed);
}
@Override
public ActionType getType() {
return ActionType.CONSOLE;
}
}

View file

@ -0,0 +1,47 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class EffectAction implements Action {
private final PotionEffectType effectType;
private final int amplifier;
private final int duration;
public EffectAction(String effectData) {
String[] parts = effectData.split(";");
PotionEffectType parsed;
try {
parsed = PotionEffectType.getByName(parts[0].toUpperCase());
} catch (Exception e) {
parsed = PotionEffectType.SPEED;
}
this.effectType = parsed != null ? parsed : PotionEffectType.SPEED;
this.amplifier = parts.length > 1 ? parseInt(parts[1], 0) : 0;
this.duration = parts.length > 2 ? parseInt(parts[2], 999999) : 999999;
}
@Override
public void execute(Player player) {
player.addPotionEffect(new PotionEffect(effectType, duration * 20, amplifier, false, false));
}
@Override
public ActionType getType() {
return ActionType.EFFECT;
}
private int parseInt(String value, int defaultValue) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
}

View file

@ -0,0 +1,37 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import org.bukkit.GameMode;
import org.bukkit.entity.Player;
public class GamemodeAction implements Action {
private final GameMode gameMode;
public GamemodeAction(String mode) {
GameMode parsed;
try {
parsed = GameMode.valueOf(mode.toUpperCase());
} catch (IllegalArgumentException e) {
parsed = switch (mode.toLowerCase()) {
case "0", "s" -> GameMode.SURVIVAL;
case "1", "c" -> GameMode.CREATIVE;
case "2", "a" -> GameMode.ADVENTURE;
case "3", "sp" -> GameMode.SPECTATOR;
default -> GameMode.SURVIVAL;
};
}
this.gameMode = parsed;
}
@Override
public void execute(Player player) {
player.setGameMode(gameMode);
}
@Override
public ActionType getType() {
return ActionType.GAMEMODE;
}
}

View file

@ -0,0 +1,27 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import com.loki.lohub.utils.PlaceholderUtil;
import com.loki.lohub.utils.TextUtil;
import org.bukkit.entity.Player;
public class MessageAction implements Action {
private final String message;
public MessageAction(String message) {
this.message = message;
}
@Override
public void execute(Player player) {
String parsed = PlaceholderUtil.parse(message, player);
player.sendMessage(TextUtil.colorize(parsed));
}
@Override
public ActionType getType() {
return ActionType.MESSAGE;
}
}

View file

@ -0,0 +1,46 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class SoundAction implements Action {
private final Sound sound;
private final float volume;
private final float pitch;
public SoundAction(String soundData) {
String[] parts = soundData.split(";");
Sound parsedSound;
try {
parsedSound = Sound.valueOf(parts[0].toUpperCase());
} catch (IllegalArgumentException e) {
parsedSound = Sound.ENTITY_EXPERIENCE_ORB_PICKUP;
}
this.sound = parsedSound;
this.volume = parts.length > 1 ? parseFloat(parts[1], 1.0f) : 1.0f;
this.pitch = parts.length > 2 ? parseFloat(parts[2], 1.0f) : 1.0f;
}
@Override
public void execute(Player player) {
player.playSound(player.getLocation(), sound, volume, pitch);
}
@Override
public ActionType getType() {
return ActionType.SOUND;
}
private float parseFloat(String value, float defaultValue) {
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
}

View file

@ -0,0 +1,61 @@
package com.loki.lohub.actions.impl;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import com.loki.lohub.utils.PlaceholderUtil;
import com.loki.lohub.utils.TextUtil;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.title.Title;
import org.bukkit.entity.Player;
import java.time.Duration;
public class TitleAction implements Action {
private final String title;
private final String subtitle;
private final int fadeIn;
private final int stay;
private final int fadeOut;
public TitleAction(String titleData) {
String[] parts = titleData.split(";");
this.title = parts.length > 0 ? parts[0] : "";
this.subtitle = parts.length > 1 ? parts[1] : "";
this.fadeIn = parts.length > 2 ? parseInt(parts[2], 10) : 10;
this.stay = parts.length > 3 ? parseInt(parts[3], 40) : 40;
this.fadeOut = parts.length > 4 ? parseInt(parts[4], 10) : 10;
}
@Override
public void execute(Player player) {
String parsedTitle = PlaceholderUtil.parse(title, player);
String parsedSubtitle = PlaceholderUtil.parse(subtitle, player);
Component titleComponent = Component.text(TextUtil.colorize(parsedTitle));
Component subtitleComponent = Component.text(TextUtil.colorize(parsedSubtitle));
Title.Times times = Title.Times.times(
Duration.ofMillis(fadeIn * 50L),
Duration.ofMillis(stay * 50L),
Duration.ofMillis(fadeOut * 50L)
);
Title title = Title.title(titleComponent, subtitleComponent, times);
player.showTitle(title);
}
@Override
public ActionType getType() {
return ActionType.TITLE;
}
private int parseInt(String value, int defaultValue) {
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
return defaultValue;
}
}
}

View file

@ -0,0 +1,35 @@
package com.loki.lohub.commands;
import com.loki.lohub.LoHub;
import com.loki.lohub.utils.TextUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class HubCommand implements CommandExecutor {
private final LoHub plugin;
public HubCommand(LoHub plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(TextUtil.colorize("&cThis command is only for players!"));
return true;
}
if (plugin.getSpawnManager().getSpawn() == null) {
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-spawn")));
return true;
}
plugin.getSpawnManager().teleportToSpawn(player);
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.spawn-teleport")));
return true;
}
}

View file

@ -0,0 +1,38 @@
package com.loki.lohub.commands;
import com.loki.lohub.LoHub;
import com.loki.lohub.utils.TextUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
public class LoHubCommand implements CommandExecutor {
private final LoHub plugin;
public LoHubCommand(LoHub plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!sender.hasPermission("lohub.admin")) {
sender.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-permission")));
return true;
}
if (args.length == 0) {
sender.sendMessage(TextUtil.colorize("&7LoHub v" + plugin.getDescription().getVersion()));
sender.sendMessage(TextUtil.colorize("&7Use: &e/lohub reload"));
return true;
}
if (args[0].equalsIgnoreCase("reload")) {
plugin.getConfigManager().reload();
sender.sendMessage(TextUtil.colorize("&aConfiguration reloaded!"));
return true;
}
return true;
}
}

View file

@ -0,0 +1,42 @@
package com.loki.lohub.commands;
import com.loki.lohub.LoHub;
import com.loki.lohub.utils.TextUtil;
import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
public class SetHubCommand implements CommandExecutor {
private final LoHub plugin;
public SetHubCommand(LoHub plugin) {
this.plugin = plugin;
}
@Override
public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
if (!(sender instanceof Player player)) {
sender.sendMessage(TextUtil.colorize("&cThis command is only for players!"));
return true;
}
if (!player.hasPermission("lohub.admin")) {
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.no-permission")));
return true;
}
plugin.getSpawnManager().setSpawn(player.getLocation());
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.spawn-set")));
plugin.getRegionManager().deleteHubRegion();
plugin.getRegionManager().createHubRegion();
if (plugin.getConfig().getBoolean("worldguard.auto-create-region")) {
player.sendMessage(TextUtil.colorize(plugin.getConfig().getString("messages.region-created")));
}
return true;
}
}

View file

@ -0,0 +1,56 @@
package com.loki.lohub.config;
import com.loki.lohub.LoHub;
import org.bukkit.configuration.file.FileConfiguration;
public class ConfigManager {
private final LoHub plugin;
private FileConfiguration config;
public ConfigManager(LoHub plugin) {
this.plugin = plugin;
this.config = plugin.getConfig();
}
public void reload() {
plugin.reloadConfig();
this.config = plugin.getConfig();
}
public FileConfiguration getConfig() {
return config;
}
public boolean isProtectionEnabled() {
return config.getBoolean("protection.enabled", true);
}
public boolean isBlockBreakProtected() {
return config.getBoolean("protection.block-break", true);
}
public boolean isBlockPlaceProtected() {
return config.getBoolean("protection.block-place", true);
}
public boolean isPvPProtected() {
return config.getBoolean("protection.pvp", true);
}
public boolean isItemDropProtected() {
return config.getBoolean("protection.item-drop", true);
}
public boolean isItemPickupProtected() {
return config.getBoolean("protection.item-pickup", true);
}
public boolean isFoodLevelProtected() {
return config.getBoolean("protection.food-level", true);
}
public boolean isMobSpawningProtected() {
return config.getBoolean("protection.mob-spawning", true);
}
}

View file

@ -0,0 +1,104 @@
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.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.FoodLevelChangeEvent;
import org.bukkit.event.player.PlayerDropItemEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerPickupItemEvent;
public class HubProtectionListener implements Listener {
private final LoHub plugin;
public HubProtectionListener(LoHub plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
if (plugin.getConfig().getBoolean("spawn.teleport-on-join", true)) {
plugin.getSpawnManager().teleportToSpawn(event.getPlayer());
}
}
@EventHandler
public void onBlockBreak(BlockBreakEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return;
Player player = event.getPlayer();
if (player.hasPermission("lohub.bypass.protection")) return;
if (plugin.getConfigManager().isBlockBreakProtected()) {
event.setCancelled(true);
}
}
@EventHandler
public void onBlockPlace(BlockPlaceEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return;
Player player = event.getPlayer();
if (player.hasPermission("lohub.bypass.protection")) return;
if (plugin.getConfigManager().isBlockPlaceProtected()) {
event.setCancelled(true);
}
}
@EventHandler
public void onPvP(EntityDamageByEntityEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return;
if (!(event.getDamager() instanceof Player)) return;
if (!(event.getEntity() instanceof Player)) return;
Player damager = (Player) event.getDamager();
if (damager.hasPermission("lohub.bypass.protection")) return;
if (plugin.getConfigManager().isPvPProtected()) {
event.setCancelled(true);
}
}
@EventHandler
public void onItemDrop(PlayerDropItemEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return;
Player player = event.getPlayer();
if (player.hasPermission("lohub.bypass.protection")) return;
if (plugin.getConfigManager().isItemDropProtected()) {
event.setCancelled(true);
}
}
@EventHandler
public void onItemPickup(PlayerPickupItemEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return;
Player player = event.getPlayer();
if (player.hasPermission("lohub.bypass.protection")) return;
if (plugin.getConfigManager().isItemPickupProtected()) {
event.setCancelled(true);
}
}
@EventHandler
public void onFoodLevelChange(FoodLevelChangeEvent event) {
if (!plugin.getConfigManager().isProtectionEnabled()) return;
if (!(event.getEntity() instanceof Player)) return;
Player player = (Player) event.getEntity();
if (player.hasPermission("lohub.bypass.protection")) return;
if (plugin.getConfigManager().isFoodLevelProtected()) {
event.setCancelled(true);
}
}
}

View file

@ -0,0 +1,208 @@
package com.loki.lohub.listeners;
import com.loki.lohub.LoHub;
import com.loki.lohub.utils.TextUtil;
import net.kyori.adventure.text.Component;
import org.bukkit.Color;
import org.bukkit.FireworkEffect;
import org.bukkit.Location;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Firework;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.event.player.PlayerRespawnEvent;
import org.bukkit.inventory.meta.FireworkMeta;
import java.util.ArrayList;
import java.util.List;
public class PlayerJoinListener implements Listener {
private final LoHub plugin;
public PlayerJoinListener(LoHub plugin) {
this.plugin = plugin;
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerJoin(PlayerJoinEvent event) {
Player player = event.getPlayer();
if (isWorldDisabled(player.getWorld().getName())) {
return;
}
handleJoinMessage(event, player);
handleJoinSettings(player);
handleJoinEvents(player);
handleFirework(player);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
if (isWorldDisabled(player.getWorld().getName())) {
return;
}
if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) {
String quitMessage = plugin.getConfig().getString("join_leave_messages.quit_message", "");
if (quitMessage.isEmpty()) {
event.quitMessage(null);
} else {
event.quitMessage(Component.text(TextUtil.colorize(quitMessage.replace("%player%", player.getName()))));
}
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerRespawn(PlayerRespawnEvent event) {
Player player = event.getPlayer();
if (isWorldDisabled(player.getWorld().getName())) {
return;
}
if (plugin.getConfig().getBoolean("spawn.teleport-on-respawn", true)) {
Location spawn = plugin.getSpawnManager().getSpawn();
if (spawn != null) {
event.setRespawnLocation(spawn);
}
}
}
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerDeath(PlayerDeathEvent event) {
if (isWorldDisabled(event.getPlayer().getWorld().getName())) {
return;
}
if (plugin.getConfig().getBoolean("world_settings.disable_death_message", true)) {
event.deathMessage(null);
}
}
private void handleJoinMessage(PlayerJoinEvent event, Player player) {
if (plugin.getConfig().getBoolean("join_leave_messages.enabled", true)) {
String joinMessage = plugin.getConfig().getString("join_leave_messages.join_message", "");
if (joinMessage.isEmpty()) {
event.joinMessage(null);
} else {
event.joinMessage(Component.text(TextUtil.colorize(joinMessage.replace("%player%", player.getName()))));
}
}
}
private void handleJoinSettings(Player player) {
if (plugin.getConfig().getBoolean("join_settings.spawn_join", true)) {
Location spawn = plugin.getSpawnManager().getSpawn();
if (spawn != null) {
player.teleport(spawn);
}
}
if (plugin.getConfig().getBoolean("join_settings.heal", true)) {
player.setHealth(player.getMaxHealth());
player.setFoodLevel(20);
player.setSaturation(20);
}
if (plugin.getConfig().getBoolean("join_settings.extinguish", true)) {
player.setFireTicks(0);
}
if (plugin.getConfig().getBoolean("join_settings.clear_inventory", false)) {
player.getInventory().clear();
}
}
private void handleJoinEvents(Player player) {
List<String> actions = plugin.getConfig().getStringList("join_events");
if (!actions.isEmpty()) {
plugin.getActionManager().executeActions(player, actions, false);
}
}
private void handleFirework(Player player) {
if (!plugin.getConfig().getBoolean("join_settings.firework.enabled", false)) {
return;
}
boolean firstJoinOnly = plugin.getConfig().getBoolean("join_settings.firework.first_join_only", true);
if (firstJoinOnly && player.hasPlayedBefore()) {
return;
}
Location loc = player.getLocation();
Firework firework = (Firework) loc.getWorld().spawnEntity(loc, EntityType.FIREWORK);
FireworkMeta meta = firework.getFireworkMeta();
String typeStr = plugin.getConfig().getString("join_settings.firework.type", "BALL_LARGE");
FireworkEffect.Type type;
try {
type = FireworkEffect.Type.valueOf(typeStr);
} catch (IllegalArgumentException e) {
type = FireworkEffect.Type.BALL_LARGE;
}
List<Color> colors = new ArrayList<>();
for (String colorStr : plugin.getConfig().getStringList("join_settings.firework.colors")) {
Color color = parseColor(colorStr);
if (color != null) {
colors.add(color);
}
}
if (colors.isEmpty()) {
colors.add(Color.AQUA);
}
FireworkEffect effect = FireworkEffect.builder()
.with(type)
.withColor(colors)
.flicker(plugin.getConfig().getBoolean("join_settings.firework.flicker", true))
.trail(plugin.getConfig().getBoolean("join_settings.firework.trail", true))
.build();
meta.addEffect(effect);
meta.setPower(plugin.getConfig().getInt("join_settings.firework.power", 1));
firework.setFireworkMeta(meta);
}
private Color parseColor(String colorStr) {
return switch (colorStr.toUpperCase()) {
case "AQUA" -> Color.AQUA;
case "BLACK" -> Color.BLACK;
case "BLUE" -> Color.BLUE;
case "FUCHSIA" -> Color.FUCHSIA;
case "GRAY" -> Color.GRAY;
case "GREEN" -> Color.GREEN;
case "LIME" -> Color.LIME;
case "MAROON" -> Color.MAROON;
case "NAVY" -> Color.NAVY;
case "OLIVE" -> Color.OLIVE;
case "ORANGE" -> Color.ORANGE;
case "PURPLE" -> Color.PURPLE;
case "RED" -> Color.RED;
case "SILVER" -> Color.SILVER;
case "TEAL" -> Color.TEAL;
case "WHITE" -> Color.WHITE;
case "YELLOW" -> Color.YELLOW;
default -> null;
};
}
private boolean isWorldDisabled(String worldName) {
List<String> disabledWorlds = plugin.getConfig().getStringList("disabled-worlds.worlds");
boolean invert = plugin.getConfig().getBoolean("disabled-worlds.invert", false);
boolean isInList = disabledWorlds.contains(worldName);
return invert ? !isInList : isInList;
}
}

View file

@ -0,0 +1,98 @@
package com.loki.lohub.managers;
import com.loki.lohub.LoHub;
import com.loki.lohub.actions.Action;
import com.loki.lohub.actions.ActionType;
import com.loki.lohub.actions.impl.*;
import org.bukkit.entity.Player;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ActionManager {
private final LoHub plugin;
private static final Pattern ACTION_PATTERN = Pattern.compile("\\[([A-Z]+)]\\s*(.*)");
public ActionManager(LoHub plugin) {
this.plugin = plugin;
}
public List<Action> parseActions(List<String> actionStrings) {
List<Action> actions = new ArrayList<>();
for (String actionString : actionStrings) {
Action action = parseAction(actionString);
if (action != null) {
actions.add(action);
}
}
return actions;
}
public Action parseAction(String actionString) {
if (actionString == null || actionString.isEmpty()) {
return null;
}
Matcher matcher = ACTION_PATTERN.matcher(actionString);
if (!matcher.matches()) {
plugin.getLogger().warning("Invalid action format: " + actionString);
return null;
}
String typeStr = matcher.group(1);
String data = matcher.group(2);
ActionType type = ActionType.fromString(typeStr);
return switch (type) {
case MESSAGE -> new MessageAction(data);
case BROADCAST -> new BroadcastAction(data);
case TITLE -> new TitleAction(data);
case ACTIONBAR -> new ActionbarAction(data);
case SOUND -> new SoundAction(data);
case COMMAND -> new CommandAction(data);
case CONSOLE -> new ConsoleAction(data);
case GAMEMODE -> new GamemodeAction(data);
case EFFECT -> new EffectAction(data);
case CLOSE -> new CloseAction();
default -> {
plugin.getLogger().warning("Unknown action type: " + typeStr);
yield null;
}
};
}
public void executeActions(Player player, List<Action> actions) {
for (Action action : actions) {
try {
action.execute(player);
} catch (Exception e) {
plugin.getLogger().severe("Error executing action " + action.getType() + ": " + e.getMessage());
e.printStackTrace();
}
}
}
public void executeActions(Player player, List<String> actionStrings, boolean parse) {
if (parse) {
List<Action> actions = parseActions(actionStrings);
executeActions(player, actions);
} else {
for (String actionString : actionStrings) {
Action action = parseAction(actionString);
if (action != null) {
try {
action.execute(player);
} catch (Exception e) {
plugin.getLogger().severe("Error executing action: " + e.getMessage());
}
}
}
}
}
}

View file

@ -0,0 +1,60 @@
package com.loki.lohub.managers;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class CooldownManager {
private final Map<String, Map<UUID, Long>> cooldowns = new HashMap<>();
public void setCooldown(String key, UUID playerId, int seconds) {
cooldowns.computeIfAbsent(key, k -> new HashMap<>())
.put(playerId, System.currentTimeMillis() + (seconds * 1000L));
}
public boolean hasCooldown(String key, UUID playerId) {
Map<UUID, Long> keyCooldowns = cooldowns.get(key);
if (keyCooldowns == null) {
return false;
}
Long expireTime = keyCooldowns.get(playerId);
if (expireTime == null) {
return false;
}
if (System.currentTimeMillis() >= expireTime) {
keyCooldowns.remove(playerId);
return false;
}
return true;
}
public int getRemainingSeconds(String key, UUID playerId) {
Map<UUID, Long> keyCooldowns = cooldowns.get(key);
if (keyCooldowns == null) {
return 0;
}
Long expireTime = keyCooldowns.get(playerId);
if (expireTime == null) {
return 0;
}
long remaining = expireTime - System.currentTimeMillis();
return remaining > 0 ? (int) (remaining / 1000) : 0;
}
public void removeCooldown(String key, UUID playerId) {
Map<UUID, Long> keyCooldowns = cooldowns.get(key);
if (keyCooldowns != null) {
keyCooldowns.remove(playerId);
}
}
public void clearAll() {
cooldowns.clear();
}
}

View file

@ -0,0 +1,130 @@
package com.loki.lohub.managers;
import com.loki.lohub.LoHub;
import com.sk89q.worldedit.bukkit.BukkitAdapter;
import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldguard.WorldGuard;
import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion;
import com.sk89q.worldguard.protection.regions.ProtectedRegion;
import com.sk89q.worldguard.protection.regions.RegionContainer;
import org.bukkit.Location;
import org.bukkit.World;
public class RegionManager {
private final LoHub plugin;
private static final String HUB_REGION_NAME = "lohub_spawn";
public RegionManager(LoHub plugin) {
this.plugin = plugin;
}
public void createHubRegion() {
if (!plugin.getConfig().getBoolean("worldguard.auto-create-region", true)) {
plugin.getLogger().info("WorldGuard region auto-creation is disabled");
return;
}
if (!isWorldGuardAvailable()) {
plugin.getLogger().warning("WorldGuard not found! Region will not be created.");
return;
}
Location spawn = plugin.getSpawnManager().getSpawn();
if (spawn == null || spawn.getWorld() == null) {
plugin.getLogger().warning("Spawn not set! Use /sethub");
return;
}
World world = spawn.getWorld();
int radius = plugin.getConfig().getInt("worldguard.region-radius", 100);
try {
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
com.sk89q.worldguard.protection.managers.RegionManager wgRegionManager = container.get(BukkitAdapter.adapt(world));
if (wgRegionManager == null) {
plugin.getLogger().warning("Failed to get RegionManager for world " + world.getName());
return;
}
ProtectedRegion existingRegion = wgRegionManager.getRegion(HUB_REGION_NAME);
if (existingRegion != null) {
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' already exists");
return;
}
BlockVector3 min = BlockVector3.at(
spawn.getBlockX() - radius,
world.getMinHeight(),
spawn.getBlockZ() - radius
);
BlockVector3 max = BlockVector3.at(
spawn.getBlockX() + radius,
world.getMaxHeight(),
spawn.getBlockZ() + radius
);
ProtectedCuboidRegion region = new ProtectedCuboidRegion(HUB_REGION_NAME, min, max);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.PVP,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.BLOCK_BREAK,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.BLOCK_PLACE,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.DAMAGE_ANIMALS,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.MOB_SPAWNING,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.LEAF_DECAY,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.ITEM_DROP,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
region.setFlag(com.sk89q.worldguard.protection.flags.Flags.ITEM_PICKUP,
com.sk89q.worldguard.protection.flags.StateFlag.State.DENY);
wgRegionManager.addRegion(region);
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' created around spawn (radius: " + radius + " blocks)");
plugin.getLogger().info("Coordinates: " + min + " -> " + max);
} catch (Exception e) {
plugin.getLogger().severe("Error creating WorldGuard region: " + e.getMessage());
e.printStackTrace();
}
}
public void deleteHubRegion() {
if (!isWorldGuardAvailable()) {
return;
}
Location spawn = plugin.getSpawnManager().getSpawn();
if (spawn == null || spawn.getWorld() == null) {
return;
}
try {
RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer();
com.sk89q.worldguard.protection.managers.RegionManager wgRegionManager = container.get(BukkitAdapter.adapt(spawn.getWorld()));
if (wgRegionManager != null) {
wgRegionManager.removeRegion(HUB_REGION_NAME);
plugin.getLogger().info("Region '" + HUB_REGION_NAME + "' deleted");
}
} catch (Exception e) {
plugin.getLogger().severe("Error deleting region: " + e.getMessage());
}
}
private boolean isWorldGuardAvailable() {
try {
Class.forName("com.sk89q.worldguard.WorldGuard");
return plugin.getServer().getPluginManager().isPluginEnabled("WorldGuard");
} catch (ClassNotFoundException e) {
return false;
}
}
}

View file

@ -0,0 +1,86 @@
package com.loki.lohub.managers;
import com.loki.lohub.LoHub;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import java.io.File;
import java.io.IOException;
public class SpawnManager {
private final LoHub plugin;
private final File spawnFile;
private FileConfiguration spawnConfig;
private Location spawnLocation;
public SpawnManager(LoHub plugin) {
this.plugin = plugin;
this.spawnFile = new File(plugin.getDataFolder(), "spawn.yml");
loadSpawn();
}
private void loadSpawn() {
if (!spawnFile.exists()) {
try {
spawnFile.createNewFile();
} catch (IOException e) {
plugin.getLogger().severe("Failed to create spawn.yml: " + e.getMessage());
}
}
spawnConfig = YamlConfiguration.loadConfiguration(spawnFile);
if (spawnConfig.contains("spawn")) {
String worldName = spawnConfig.getString("spawn.world");
double x = spawnConfig.getDouble("spawn.x");
double y = spawnConfig.getDouble("spawn.y");
double z = spawnConfig.getDouble("spawn.z");
float yaw = (float) spawnConfig.getDouble("spawn.yaw");
float pitch = (float) spawnConfig.getDouble("spawn.pitch");
World world = Bukkit.getWorld(worldName);
if (world != null) {
spawnLocation = new Location(world, x, y, z, yaw, pitch);
plugin.getLogger().info("Spawn loaded: " + worldName + " (" + x + ", " + y + ", " + z + ")");
} else {
plugin.getLogger().warning("World '" + worldName + "' not found!");
}
}
}
public void setSpawn(Location location) {
this.spawnLocation = location;
spawnConfig.set("spawn.world", location.getWorld().getName());
spawnConfig.set("spawn.x", location.getX());
spawnConfig.set("spawn.y", location.getY());
spawnConfig.set("spawn.z", location.getZ());
spawnConfig.set("spawn.yaw", location.getYaw());
spawnConfig.set("spawn.pitch", location.getPitch());
try {
spawnConfig.save(spawnFile);
plugin.getLogger().info("Spawn set: " + location.getWorld().getName() +
" (" + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ() + ")");
} catch (IOException e) {
plugin.getLogger().severe("Failed to save spawn.yml: " + e.getMessage());
}
}
public Location getSpawn() {
return spawnLocation;
}
public void teleportToSpawn(Player player) {
if (spawnLocation == null) {
return;
}
player.teleport(spawnLocation);
}
}

View file

@ -0,0 +1,156 @@
package com.loki.lohub.utils;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.enchantments.Enchantment;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemFlag;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
public class ItemBuilder {
private final ItemStack itemStack;
public ItemBuilder(Material material) {
this.itemStack = new ItemStack(material);
}
public ItemBuilder(ItemStack itemStack) {
this.itemStack = itemStack.clone();
}
public static ItemBuilder fromConfig(ConfigurationSection section) {
return fromConfig(section, null);
}
public static ItemBuilder fromConfig(ConfigurationSection section, Player player) {
String materialName = section.getString("material", "STONE").toUpperCase();
Material material;
try {
material = Material.valueOf(materialName);
} catch (IllegalArgumentException e) {
material = Material.STONE;
}
ItemBuilder builder = new ItemBuilder(material);
if (section.contains("amount")) {
builder.amount(section.getInt("amount", 1));
}
if (section.contains("display_name")) {
String name = section.getString("display_name");
builder.name(player != null ? PlaceholderUtil.parse(name, player) : name);
}
if (section.contains("lore")) {
List<String> lore = section.getStringList("lore");
builder.lore(player != null ?
lore.stream().map(line -> PlaceholderUtil.parse(line, player)).collect(Collectors.toList()) :
lore);
}
if (section.contains("glow") && section.getBoolean("glow")) {
builder.glow();
}
if (section.contains("custom_model_data")) {
builder.customModelData(section.getInt("custom_model_data"));
}
if (section.contains("item_flags")) {
section.getStringList("item_flags").forEach(flagName -> {
try {
builder.flag(ItemFlag.valueOf(flagName.toUpperCase()));
} catch (IllegalArgumentException ignored) {}
});
}
if (material == Material.PLAYER_HEAD && section.contains("skull_owner")) {
String owner = section.getString("skull_owner");
builder.skullOwner(player != null ? owner.replace("%player%", player.getName()) : owner);
}
return builder;
}
public ItemBuilder amount(int amount) {
itemStack.setAmount(Math.max(1, amount));
return this;
}
public ItemBuilder name(String name) {
ItemMeta meta = itemStack.getItemMeta();
if (meta != null) {
meta.setDisplayName(TextUtil.colorize(name));
itemStack.setItemMeta(meta);
}
return this;
}
public ItemBuilder lore(List<String> lore) {
ItemMeta meta = itemStack.getItemMeta();
if (meta != null) {
List<String> coloredLore = lore.stream()
.map(TextUtil::colorize)
.collect(Collectors.toList());
meta.setLore(coloredLore);
itemStack.setItemMeta(meta);
}
return this;
}
public ItemBuilder lore(String... lines) {
return lore(List.of(lines));
}
public ItemBuilder flag(ItemFlag... flags) {
ItemMeta meta = itemStack.getItemMeta();
if (meta != null) {
meta.addItemFlags(flags);
itemStack.setItemMeta(meta);
}
return this;
}
public ItemBuilder glow() {
ItemMeta meta = itemStack.getItemMeta();
if (meta != null) {
meta.addEnchant(Enchantment.LUCK, 1, true);
meta.addItemFlags(ItemFlag.HIDE_ENCHANTS);
itemStack.setItemMeta(meta);
}
return this;
}
public ItemBuilder customModelData(int data) {
ItemMeta meta = itemStack.getItemMeta();
if (meta != null) {
meta.setCustomModelData(data);
itemStack.setItemMeta(meta);
}
return this;
}
public ItemBuilder skullOwner(String owner) {
if (itemStack.getType() == Material.PLAYER_HEAD) {
SkullMeta meta = (SkullMeta) itemStack.getItemMeta();
if (meta != null) {
meta.setOwner(owner);
itemStack.setItemMeta(meta);
}
}
return this;
}
public ItemStack build() {
return itemStack;
}
}

View file

@ -0,0 +1,55 @@
package com.loki.lohub.utils;
import me.clip.placeholderapi.PlaceholderAPI;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
public class PlaceholderUtil {
private static boolean placeholderAPIEnabled = false;
public static void init() {
placeholderAPIEnabled = Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI");
}
public static String parse(String text, Player player) {
if (text == null) {
return "";
}
text = parseInternalPlaceholders(text, player);
if (placeholderAPIEnabled && player != null) {
text = PlaceholderAPI.setPlaceholders(player, text);
}
return text;
}
private static String parseInternalPlaceholders(String text, Player player) {
if (player != null) {
text = text.replace("%player%", player.getName());
text = text.replace("%player_displayname%", player.getDisplayName());
if (text.contains("%location%")) {
Location loc = player.getLocation();
text = text.replace("%location%",
loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ());
}
if (text.contains("%world%")) {
text = text.replace("%world%", player.getWorld().getName());
}
}
text = text.replace("%online%", String.valueOf(Bukkit.getOnlinePlayers().size()));
text = text.replace("%online_max%", String.valueOf(Bukkit.getMaxPlayers()));
return text;
}
public static boolean isPlaceholderAPIEnabled() {
return placeholderAPIEnabled;
}
}

View file

@ -0,0 +1,72 @@
package com.loki.lohub.utils;
import net.md_5.bungee.api.ChatColor;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class TextUtil {
private static final Pattern HEX_PATTERN = Pattern.compile("&#([A-Fa-f0-9]{6})");
public static String colorize(String text) {
if (text == null || text.isEmpty()) {
return text;
}
text = translateHexCodes(text);
text = ChatColor.translateAlternateColorCodes('&', text);
return text;
}
public static List<String> colorize(List<String> lines) {
return lines.stream()
.map(TextUtil::colorize)
.collect(Collectors.toList());
}
private static String translateHexCodes(String text) {
Matcher matcher = HEX_PATTERN.matcher(text);
StringBuffer buffer = new StringBuffer();
while (matcher.find()) {
String hexCode = matcher.group(1);
String replacement = ChatColor.of("#" + hexCode).toString();
matcher.appendReplacement(buffer, replacement);
}
matcher.appendTail(buffer);
return buffer.toString();
}
public static String strip(String text) {
return ChatColor.stripColor(text);
}
public static String joinFrom(int startIndex, String[] args) {
if (args == null || startIndex >= args.length) {
return "";
}
StringBuilder builder = new StringBuilder();
for (int i = startIndex; i < args.length; i++) {
builder.append(args[i]);
if (i < args.length - 1) {
builder.append(" ");
}
}
return builder.toString();
}
public static String listToString(List<String> list) {
if (list == null || list.isEmpty()) {
return "";
}
return String.join("\n", list);
}
}

View file

@ -0,0 +1,343 @@
# ╔══════════════════════════════════════════════════════════════════════════════╗
# ║ LoHub Configuration ║
# ║ Hub plugin for Paper/Folia 1.20.1+ ║
# ║ Version: 1.5.5-1.20.1 ║
# ║ Compatible with DeluxeHub config format ║
# ╚══════════════════════════════════════════════════════════════════════════════╝
#
# BUILT-IN PLACEHOLDERS:
# %player% - Player name
# %player_displayname% - Player display name
# %location% - Player location (x, y, z)
# %world% - World name
# %online% - Online players count
# %online_max% - Max players
#
# ACTIONS (for join_events, custom_join_items, etc):
# [MESSAGE] text - Send message to player
# [BROADCAST] text - Broadcast to all players
# [TITLE] title;subtitle;fadeIn;stay;fadeOut - Send title
# [ACTIONBAR] text - Send actionbar message
# [SOUND] sound - Play sound
# [COMMAND] command - Execute as player
# [CONSOLE] command - Execute as console
# [GAMEMODE] mode - Change gamemode (survival/creative/adventure/spectator)
# [EFFECT] effect;level - Give potion effect
# [CLOSE] - Close inventory
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | GENERAL SETTINGS |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# Check for updates (recommended)
check-updates: false
# Disable plugin in specific worlds
disabled-worlds:
invert: false
worlds:
- world_nether
- world_the_end
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | SPAWN SETTINGS |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
spawn:
# Teleport players to spawn on join
teleport-on-join: true
# Teleport players to spawn on respawn
teleport-on-respawn: true
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | WORLDGUARD INTEGRATION |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
worldguard:
# Auto-create WorldGuard region around spawn
auto-create-region: true
# Region radius in blocks
region-radius: 100
# Region name (don't change unless you know what you're doing)
region-name: "lohub_spawn"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | WORLD PROTECTION |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
world_settings:
# Player
disable_hunger_loss: true
disable_fall_damage: true
disable_player_pvp: true
disable_void_death: true
disable_fire_damage: true
disable_drowning: true
disable_off_hand_swap: true
# Misc
disable_weather_change: true
disable_death_message: true
disable_mob_spawning: true
# Item entities
disable_item_drop: true
disable_item_pickup: true
# Blocks
disable_block_break: true
disable_block_place: true
disable_block_interact: true
disable_block_burn: true
disable_block_fire_spread: true
disable_block_leaf_decay: true
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | LAUNCHPAD |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
launchpad:
enabled: true
launch_power: 3.0
launch_power_y: 1.0
# Blocks required: pressure plate on top of redstone block
top_block: STONE_PRESSURE_PLATE
bottom_block: REDSTONE_BLOCK
actions:
- '[SOUND] ENTITY_BAT_TAKEOFF'
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | DOUBLE JUMP |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
double_jump:
enabled: true
launch_power: 1.0
launch_power_y: 0.9
cooldown: 3
actions:
- '[SOUND] ENTITY_BAT_TAKEOFF'
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | COMMAND BLOCKER |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
command_block:
enabled: true
blocked_commands:
- /pl
- /plugins
- /?
- /bukkit:?
- /bukkit:plugins
- /bukkit:pl
- /bukkit:help
- /ver
- /version
- /bukkit:version
- /bukkit:ver
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | ANTI-SWEAR |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
anti_swear:
enabled: false
blocked_words:
- fuck
- shit
- bitch
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | PLAYER JOIN |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
join_leave_messages:
enabled: true
join_message: "&#6BCB77+ &#FFD700%player% &#AAAAAAconnected"
quit_message: "&#FF6B6B- &#FFD700%player% &#AAAAAAdisconnected"
join_events:
- "[MESSAGE] &#FFD700╔═══════════════════════════════╗"
- "[MESSAGE] &r"
- "[MESSAGE] &r &#6BCB77Welcome, &#FFD700%player%&#6BCB77!"
- "[MESSAGE] &r"
- "[MESSAGE] &r &#00D4FFWebsite: &#FFFFFFwww.example.net"
- "[MESSAGE] &r &#FF6B6BStore: &#FFFFFFstore.example.net"
- "[MESSAGE] &r &#9B59B6Discord: &#FFFFFFdiscord.example.net"
- "[MESSAGE] &r"
- "[MESSAGE] &#FFD700╚═══════════════════════════════╝"
- "[TITLE] &#6BCB77W&#62C973E&#5AC76FL&#51C56BC&#49C367O&#40C163M&#38BF5FE;&#FFD700%player%;10;40;10"
- "[SOUND] ENTITY_PLAYER_LEVELUP"
- "[GAMEMODE] survival"
join_settings:
spawn_join: true
heal: true
extinguish: true
clear_inventory: false
firework:
enabled: true
first_join_only: true
type: BALL_LARGE
power: 1
flicker: true
trail: true
colors:
- AQUA
- RED
- TEAL
- WHITE
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | CUSTOM JOIN ITEMS |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
custom_join_items:
enabled: true
disable_inventory_movement: true
items:
info:
material: BOOK
amount: 1
slot: 0
display_name: "&#FFD700I&#FFC700n&#FFB700f&#FFA700o&#FF9700r&#FF8700m&#FF7700a&#FF6700t&#FF5700i&#FF4700o&#FF3700n"
lore:
- "&#AAAAAARight-click for server info!"
actions:
- "[MESSAGE] &r"
- "[MESSAGE] &#FFD700╔═══ Server Information ═══╗"
- "[MESSAGE] &r"
- "[MESSAGE] &#00D4FFWebsite: &#FFFFFFwww.example.net"
- "[MESSAGE] &#FF6B6BStore: &#FFFFFFstore.example.net"
- "[MESSAGE] &#9B59B6Discord: &#FFFFFFdiscord.example.net"
- "[MESSAGE] &r"
- "[MESSAGE] &#FFD700╚═══════════════════════════╝"
- "[SOUND] BLOCK_NOTE_BLOCK_PLING"
compass:
material: COMPASS
amount: 1
slot: 4
display_name: "&#6BCB77S&#62C973e&#5AC76Fr&#51C56Bv&#49C367e&#40C163r &#38BF5FS&#2FBD5Be&#27BB57l&#1EB953e&#16B74Fc&#0DB54Bt&#05B347o&#05B347r"
lore:
- "&#AAAAAARight-click to choose server!"
actions:
- "[MESSAGE] &#FF6B6BServer selector not implemented yet!"
- "[SOUND] ENTITY_VILLAGER_NO"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | PLAYER HIDER |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
player_hider:
enabled: true
slot: 8
disable_inventory_movement: true
cooldown: 3
not_hidden:
material: LIME_DYE
amount: 1
display_name: '&#6BCB77Players &#AAAAAA> &#6BCB77Shown &#888888(Right-Click)'
lore:
- '&#AAAAAAClick to hide all players!'
hidden:
material: GRAY_DYE
amount: 1
display_name: '&#FF6B6BPlayers &#AAAAAA> &#FF6B6BHidden &#888888(Right-Click)'
lore:
- '&#AAAAAAClick to show all players!'
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | SCOREBOARD |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
scoreboard:
enabled: false
display_delay:
server_enter: 60
world_change: 40
refresh:
enabled: true
rate: 200
title: "&#FFD700L&#FFC700o&#FFB700H&#FFA700u&#FF9700b &#888888(%online%/%online_max%)"
lines:
- "&#AAAAAA━━━━━━━━━━━━━━━━━━━━━"
- "&#6BCB77Player:"
- " &#FFFFFF%player%"
- ""
- "&#6BCB77Rank:"
- " &#FFFFFF%vault_rank%"
- "&#AAAAAA━━━━━━━━━━━━━━━━━━━━━"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | TABLIST |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
tablist:
enabled: false
refresh:
enabled: true
rate: 400
header:
- ""
- "&#FFD700L&#FFC700o&#FFB700H&#FFA700u&#FF9700b &#888888(%online%/%online_max%)"
- ""
footer:
- ""
- "&#00D4FFWebsite &#FFFFFFwww.example.net"
- "&#FF6B6BStore &#FFFFFFstore.example.net"
- ""
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | ANNOUNCEMENTS |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
announcements:
enabled: false
delay: 60
required_players: 1
sound:
enabled: true
value: BLOCK_NOTE_BLOCK_PLING
volume: 1.0
pitch: 1.0
announcements:
welcome:
- "&r"
- "&#FFD700╔═══ Announcement ═══╗"
- "&#AAAAAAWelcome to our server!"
- "&#FFD700╚═══════════════════════╝"
- "&r"
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
# | MESSAGES |
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~#
messages:
prefix: "&#00D4FF[&#00D4FFL&#00CAF7o&#00C0EEH&#00B7E6u&#00ADDDb&#0099CC]"
spawn-set: "&#6BCB77Spawn set successfully!"
spawn-teleport: "&#6BCB77Teleporting to spawn..."
no-spawn: "&#FF6B6BSpawn not set! Use /sethub"
no-permission: "&#FF6B6BYou don't have permission!"
players-only: "&#FF6B6BThis command is only for players!"
config-reloaded: "&#6BCB77Configuration reloaded!"
usage: "&#FFD700Usage: /lohub reload"

View file

@ -0,0 +1,40 @@
name: LoHub
version: '1.5.5-1.20.1'
main: com.loki.lohub.LoHub
api-version: '1.20'
folia-supported: true
author: loki
description: Hub plugin for Paper/Folia with WorldGuard integration
softdepend:
- WorldGuard
- WorldEdit
commands:
hub:
description: Teleport to spawn
usage: /hub
permission: lohub.hub
aliases: [spawn, хаб, спавн]
sethub:
description: Set hub spawn location
usage: /sethub
permission: lohub.admin
aliases: [setspawn, установитьспавн]
lohub:
description: LoHub admin command
usage: /lohub [reload]
permission: lohub.admin
permissions:
lohub.hub:
description: Can use /hub command
default: true
lohub.admin:
description: Admin permissions
default: op
lohub.bypass.protection:
description: Bypass world protection
default: op