port: compat layer
- add compat/Adventure (BukkitAudiences lifecycle with legacy fallback) - add compat/Msg (send/broadcast/actionBar/title/legacy/plain/displayName/playerListName/kick/itemMeta/inventoryTitle) - wire Adventure.init/close in LoChat onEnable/onDisable - remove unused reflection-based utils/platform/AdventureManager
This commit is contained in:
parent
dd725ad255
commit
88e4e68cca
4 changed files with 227 additions and 96 deletions
|
|
@ -47,7 +47,8 @@ public final class LoChat extends JavaPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void onEnable() {
|
public void onEnable() {
|
||||||
instance = this;
|
instance = this;
|
||||||
getLogger().info("Загрузка LoChat v" + getPluginMeta().getVersion() + " для Paper/Folia " + Bukkit.getMinecraftVersion() + "...");
|
com.loki.lochat.compat.Adventure.init(this);
|
||||||
|
getLogger().info("Загрузка LoChat v" + getDescription().getVersion() + " для Spigot " + Bukkit.getBukkitVersion() + "...");
|
||||||
|
|
||||||
// Инициализация
|
// Инициализация
|
||||||
initializer = new PluginInitializer(this);
|
initializer = new PluginInitializer(this);
|
||||||
|
|
@ -95,6 +96,7 @@ public final class LoChat extends JavaPlugin {
|
||||||
@Override
|
@Override
|
||||||
public void onDisable() {
|
public void onDisable() {
|
||||||
shutdown.shutdown(serviceRegistry, autoMessageManager, discordIntegration, gradientModule);
|
shutdown.shutdown(serviceRegistry, autoMessageManager, discordIntegration, gradientModule);
|
||||||
|
com.loki.lochat.compat.Adventure.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reload() {
|
public void reload() {
|
||||||
|
|
|
||||||
50
src/main/java/com/loki/lochat/compat/Adventure.java
Normal file
50
src/main/java/com/loki/lochat/compat/Adventure.java
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
package com.loki.lochat.compat;
|
||||||
|
|
||||||
|
import net.kyori.adventure.platform.bukkit.BukkitAudiences;
|
||||||
|
|
||||||
|
import org.bukkit.plugin.Plugin;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds BukkitAudiences for Spigot. Falls back to legacy text if creation fails.
|
||||||
|
*/
|
||||||
|
public final class Adventure {
|
||||||
|
|
||||||
|
private static BukkitAudiences audiences;
|
||||||
|
private static boolean fallback;
|
||||||
|
|
||||||
|
private Adventure() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init(Plugin plugin) {
|
||||||
|
try {
|
||||||
|
audiences = BukkitAudiences.create(plugin);
|
||||||
|
fallback = false;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
audiences = null;
|
||||||
|
fallback = true;
|
||||||
|
plugin.getLogger().warning(
|
||||||
|
"[LoChat] BukkitAudiences init failed, falling back to legacy text: " + t.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void close() {
|
||||||
|
if (audiences != null) {
|
||||||
|
try {
|
||||||
|
audiences.close();
|
||||||
|
} catch (Exception ignored) {
|
||||||
|
}
|
||||||
|
audiences = null;
|
||||||
|
}
|
||||||
|
fallback = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static BukkitAudiences audiences() {
|
||||||
|
return audiences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isFallback() {
|
||||||
|
return fallback || audiences == null;
|
||||||
|
}
|
||||||
|
}
|
||||||
174
src/main/java/com/loki/lochat/compat/Msg.java
Normal file
174
src/main/java/com/loki/lochat/compat/Msg.java
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
package com.loki.lochat.compat;
|
||||||
|
|
||||||
|
import net.kyori.adventure.text.Component;
|
||||||
|
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
|
||||||
|
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
|
||||||
|
import net.kyori.adventure.title.Title;
|
||||||
|
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.inventory.meta.ItemMeta;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Static helpers for sending Adventure components on Spigot via BukkitAudiences.
|
||||||
|
* Falls back to legacy String when audiences not available.
|
||||||
|
*/
|
||||||
|
public final class Msg {
|
||||||
|
|
||||||
|
private static final LegacyComponentSerializer LEGACY = LegacyComponentSerializer.builder()
|
||||||
|
.character('§')
|
||||||
|
.hexColors()
|
||||||
|
.useUnusualXRepeatedCharacterHexFormat()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
private static final PlainTextComponentSerializer PLAIN = PlainTextComponentSerializer.plainText();
|
||||||
|
|
||||||
|
private Msg() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void send(CommandSender sender, Component component) {
|
||||||
|
if (sender == null || component == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Adventure.isFallback() && Adventure.audiences() != null) {
|
||||||
|
try {
|
||||||
|
Adventure.audiences().sender(sender).sendMessage(component);
|
||||||
|
return;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sender.sendMessage(legacy(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void send(Collection<? extends CommandSender> senders, Component component) {
|
||||||
|
if (senders == null || component == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (CommandSender s : senders) {
|
||||||
|
send(s, component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void broadcast(Component component) {
|
||||||
|
if (component == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Adventure.isFallback() && Adventure.audiences() != null) {
|
||||||
|
try {
|
||||||
|
Adventure.audiences().all().sendMessage(component);
|
||||||
|
return;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String legacy = legacy(component);
|
||||||
|
Bukkit.getOnlinePlayers().forEach(p -> p.sendMessage(legacy));
|
||||||
|
Bukkit.getConsoleSender().sendMessage(legacy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void actionBar(Player player, Component component) {
|
||||||
|
if (player == null || component == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Adventure.isFallback() && Adventure.audiences() != null) {
|
||||||
|
try {
|
||||||
|
Adventure.audiences().player(player).sendActionBar(component);
|
||||||
|
return;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback: send as chat
|
||||||
|
player.sendMessage(legacy(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void title(Player player, Component title, Component subtitle, Title.Times times) {
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Component t = title != null ? title : Component.empty();
|
||||||
|
Component s = subtitle != null ? subtitle : Component.empty();
|
||||||
|
Title.Times tm = times != null ? times : Title.Times.times(
|
||||||
|
Duration.ofMillis(500), Duration.ofMillis(3000), Duration.ofMillis(500));
|
||||||
|
if (!Adventure.isFallback() && Adventure.audiences() != null) {
|
||||||
|
try {
|
||||||
|
Adventure.audiences().player(player).showTitle(Title.title(t, s, tm));
|
||||||
|
return;
|
||||||
|
} catch (Throwable ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Fallback via Bukkit API (legacy strings, 1.20.1 supports titles)
|
||||||
|
player.sendTitle(legacy(t), legacy(s),
|
||||||
|
(int) (tm.fadeIn().toMillis() / 50),
|
||||||
|
(int) (tm.stay().toMillis() / 50),
|
||||||
|
(int) (tm.fadeOut().toMillis() / 50));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String legacy(Component component) {
|
||||||
|
if (component == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return LEGACY.serialize(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String plain(Component component) {
|
||||||
|
if (component == null) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return PLAIN.serialize(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setDisplayName(Player player, Component component) {
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.setDisplayName(component == null ? "" : legacy(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setPlayerListName(Player player, Component component) {
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.setPlayerListName(component == null ? "" : legacy(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void kick(Player player, Component reason) {
|
||||||
|
if (player == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String msg = reason == null ? "" : legacy(reason);
|
||||||
|
// Must be on main thread; caller should ensure via scheduler if needed
|
||||||
|
if (Bukkit.isPrimaryThread()) {
|
||||||
|
player.kickPlayer(msg);
|
||||||
|
} else {
|
||||||
|
Bukkit.getScheduler().runTask(
|
||||||
|
Bukkit.getPluginManager().getPlugin("LoChat"), () -> player.kickPlayer(msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void itemName(ItemMeta meta, Component name) {
|
||||||
|
if (meta == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
meta.setDisplayName(name == null ? null : legacy(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void itemLore(ItemMeta meta, List<Component> lore) {
|
||||||
|
if (meta == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (lore == null) {
|
||||||
|
meta.setLore(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
List<String> lines = lore.stream().map(Msg::legacy).toList();
|
||||||
|
meta.setLore(lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String inventoryTitle(Component title) {
|
||||||
|
return legacy(title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,95 +0,0 @@
|
||||||
package com.loki.lochat.utils.platform;
|
|
||||||
|
|
||||||
import org.bukkit.command.CommandSender;
|
|
||||||
import org.bukkit.entity.Player;
|
|
||||||
import org.bukkit.plugin.Plugin;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Менеджер для работы с Adventure API на Arclight/Forge серверах
|
|
||||||
*/
|
|
||||||
public class AdventureManager {
|
|
||||||
|
|
||||||
private AdventureManager() {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean adventureAvailable = false;
|
|
||||||
private static Object audiences;
|
|
||||||
|
|
||||||
public static void init(Plugin plugin) {
|
|
||||||
try {
|
|
||||||
// Проверяем наличие Adventure API
|
|
||||||
Class.forName("net.kyori.adventure.text.Component");
|
|
||||||
Class<?> audiencesClass = Class.forName("net.kyori.adventure.platform.bukkit.BukkitAudiences");
|
|
||||||
|
|
||||||
// Создаем BukkitAudiences через рефлексию
|
|
||||||
Object audiencesInstance = audiencesClass.getMethod("create", Plugin.class).invoke(null, plugin);
|
|
||||||
audiences = audiencesInstance;
|
|
||||||
adventureAvailable = true;
|
|
||||||
|
|
||||||
plugin.getLogger().info("Adventure API обнаружен - используем нативную поддержку");
|
|
||||||
} catch (Exception e) {
|
|
||||||
adventureAvailable = false;
|
|
||||||
plugin.getLogger().info("Adventure API не найден - используем legacy режим");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void shutdown() {
|
|
||||||
if (audiences != null && adventureAvailable) {
|
|
||||||
try {
|
|
||||||
audiences.getClass().getMethod("close").invoke(audiences);
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Игнорируем ошибки при закрытии
|
|
||||||
}
|
|
||||||
audiences = null;
|
|
||||||
}
|
|
||||||
adventureAvailable = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMessage(CommandSender sender, Object message) {
|
|
||||||
if (adventureAvailable && audiences != null) {
|
|
||||||
try {
|
|
||||||
// Используем Adventure API
|
|
||||||
Object senderAudience = audiences.getClass().getMethod("sender", CommandSender.class).invoke(audiences, sender);
|
|
||||||
senderAudience.getClass()
|
|
||||||
.getMethod("sendMessage", Class.forName("net.kyori.adventure.text.Component"))
|
|
||||||
.invoke(senderAudience, message);
|
|
||||||
return;
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Fallback на legacy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Legacy fallback
|
|
||||||
if (message instanceof String) {
|
|
||||||
sender.sendMessage((String) message);
|
|
||||||
} else {
|
|
||||||
sender.sendMessage(message.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void sendMessage(Player player, Object message) {
|
|
||||||
if (adventureAvailable && audiences != null) {
|
|
||||||
try {
|
|
||||||
// Используем Adventure API
|
|
||||||
Object playerAudience = audiences.getClass().getMethod("player", Player.class).invoke(audiences, player);
|
|
||||||
playerAudience.getClass()
|
|
||||||
.getMethod("sendMessage", Class.forName("net.kyori.adventure.text.Component"))
|
|
||||||
.invoke(playerAudience, message);
|
|
||||||
return;
|
|
||||||
} catch (Exception e) {
|
|
||||||
// Fallback на legacy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Legacy fallback
|
|
||||||
if (message instanceof String) {
|
|
||||||
player.sendMessage((String) message);
|
|
||||||
} else {
|
|
||||||
player.sendMessage(message.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isAdventureAvailable() {
|
|
||||||
return adventureAvailable;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue