This commit is contained in:
kento2 2026-07-08 15:15:58 +02:00
parent 5073d933d2
commit 2af29fe6bf
16 changed files with 241 additions and 108 deletions

View file

@ -28,6 +28,7 @@ tasks {
downloadPlugins {
url("https://hangarcdn.papermc.io/plugins/ViaVersion/ViaVersion/versions/5.7.1/PAPER/ViaVersion-5.7.1.jar")
url("https://hangarcdn.papermc.io/plugins/ViaVersion/ViaBackwards/versions/5.7.1/PAPER/ViaBackwards-5.7.1.jar")
url("https://download.luckperms.net/1647/bukkit/loader/LuckPerms-Bukkit-5.5.59.jar")
}
}
}

View file

@ -1,13 +1,16 @@
package de.kentoj.scrow.bukkit;
import de.kentoj.scrow.bukkit.chatstyle.ChatStyleListener;
import de.kentoj.scrow.bukkit.chatstyle.NoPrefixPrefixCache;
import de.kentoj.scrow.bukkit.style.ChatStyleListener;
import de.kentoj.scrow.bukkit.command.economy.CoinsCommand;
import de.kentoj.scrow.bukkit.command.friends.FriendCommand;
import de.kentoj.scrow.bukkit.command.instance.InstanceCache;
import de.kentoj.scrow.bukkit.command.instance.InstanceCommand;
import de.kentoj.scrow.bukkit.command.instance.LobbyCommand;
import de.kentoj.scrow.bukkit.command.instance.PlayCommand;
import de.kentoj.scrow.bukkit.internal.player.prefix.CachedPrefixProvider;
import de.kentoj.scrow.bukkit.internal.player.prefix.LuckPermsPrefixSetter;
import de.kentoj.scrow.bukkit.style.TabStyleListener;
import net.luckperms.api.LuckPermsProvider;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.IOException;
@ -20,17 +23,20 @@ public final class CoreImplPlugin extends JavaPlugin {
@Override
public void onEnable() {
ScrowAPISurface.initScrowAPI(this);
{
ScrowAPI.getCommandApi().register(new CoinsCommand().getRootLiteral());
ScrowAPI.getCommandApi().register(FriendCommand.create());
var instanceCache = new InstanceCache();
ScrowAPI.getCommandApi().register(InstanceCommand.create(instanceCache));
ScrowAPI.getCommandApi().register(new PlayCommand().getRootLiteral());
ScrowAPI.getCommandApi().register(new LobbyCommand().getRootLiteral());
}
var cachedPrefixProvider = new CachedPrefixProvider();
ScrowAPISurface.initScrowAPI(this, cachedPrefixProvider);
getServer().getPluginManager().registerEvents(new ChatStyleListener(new NoPrefixPrefixCache()), this);
ScrowAPI.getCommandApi().register(new CoinsCommand().getRootLiteral());
ScrowAPI.getCommandApi().register(FriendCommand.create());
var instanceCache = new InstanceCache();
ScrowAPI.getCommandApi().register(InstanceCommand.create(instanceCache));
ScrowAPI.getCommandApi().register(new PlayCommand().getRootLiteral());
ScrowAPI.getCommandApi().register(new LobbyCommand().getRootLiteral());
var luckperms = LuckPermsProvider.get();
new LuckPermsPrefixSetter(luckperms, cachedPrefixProvider).init(this);
getServer().getPluginManager().registerEvents(new ChatStyleListener(cachedPrefixProvider), this);
getServer().getPluginManager().registerEvents(new TabStyleListener(cachedPrefixProvider), this);
// TODO/FIXME
//registerServer();

View file

@ -1,7 +1,8 @@
package de.kentoj.scrow.bukkit;
import de.kentoj.kencommandapi.CommandAPI;
import de.kentoj.scrow.bukkit.internal.network.NetworkPlayerWatchdog;
import de.kentoj.scrow.bukkit.internal.player.NetworkPlayerWatchdog;
import de.kentoj.scrow.bukkit.internal.player.prefix.CachedPrefixProvider;
import de.kentoj.scrow.bukkit.internal.region.RegionManagerImpl;
import de.kentoj.scrow.bukkit.internal.region.RegionPlayerTracker;
import de.kentoj.scrow.bukkit.internal.region.RegionTask;
@ -15,6 +16,7 @@ import de.kentoj.scrowlib.instancemanager.InstanceManagerImpl;
import de.kentoj.scrowlib.messaging.InMemoyMessageBroker;
import de.kentoj.scrowlib.messaging.NatsMessageBroker;
import de.kentoj.scrowlib.player.NetworkPlayerImpl;
import de.kentoj.scrowlib.player.PlayerPrefixProvider;
import io.nats.client.Nats;
import io.nats.client.Options;
import lombok.AccessLevel;
@ -30,7 +32,7 @@ import java.util.Properties;
@NoArgsConstructor(access = AccessLevel.NONE)
public class ScrowAPISurface {
public static void initScrowAPI(Plugin plugin) {
public static void initScrowAPI(Plugin plugin, PlayerPrefixProvider prefixProvider) {
ScrowAPI.setCorePlugin(plugin);
var natsHost = System.getenv("HOST_NATS");
@ -73,6 +75,7 @@ public class ScrowAPISurface {
new PostgresFriendRequestService(ScrowAPI.getJdbi()) : new InMemoryFriendRequestService());
ScrowAPI.setFriendshipService(ScrowAPI.getJdbi() != null ?
new PostgresFriendshipService(ScrowAPI.getJdbi()) : new InMemoryFriendshipService());
ScrowAPI.setPlayerPrefixProvider(prefixProvider);
new RegionTask(new RegionPlayerTracker()).runTaskTimer(plugin, 10, 10);
new NetworkPlayerWatchdog().listen();

View file

@ -1,32 +0,0 @@
package de.kentoj.scrow.bukkit.chatstyle;
import de.kentoj.scrowlib.utils.ComponentUtils;
import io.papermc.paper.event.player.AsyncChatEvent;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@RequiredArgsConstructor
public class ChatStyleListener implements Listener {
private final PrefixCache prefixCache;
@EventHandler
public void onChat(AsyncChatEvent ev) {
Component formattedMessage = formatMessage(ev.getPlayer(), ev.message());
ev.renderer((source, sourceDisplayName, message, viewer) -> formattedMessage);
}
private Component formatMessage(Player player, Component message) {
var prefix = prefixCache.getPrefix(player.getUniqueId());
Component msg = prefix != null
? prefix.append(Component.text("").color(NamedTextColor.DARK_GRAY))
: Component.empty();
return msg.append(Component.text(player.getName() + ": ").color(NamedTextColor.GRAY))
.append(ComponentUtils.resolveURLS(message).colorIfAbsent(NamedTextColor.GRAY));
}
}

View file

@ -1,36 +0,0 @@
package de.kentoj.scrow.bukkit.chatstyle;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.plain.PlainTextComponentSerializer;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.event.user.UserDataRecalculateEvent;
import org.bukkit.Bukkit;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
public class LuckPermsPrefixCache implements PrefixCache {
private final Map<UUID, Component> cache = new HashMap<>();
// TODO load on join, unload on quit
public LuckPermsPrefixCache(LuckPerms luckPerms) {
//noinspection resource
luckPerms.getEventBus().subscribe(UserDataRecalculateEvent.class, this::onDataChange);
}
private void onDataChange(UserDataRecalculateEvent ev) {
var playerId = ev.getUser().getUniqueId();
if (Bukkit.getPlayer(playerId) == null) return;
var prefix = ev.getUser().getCachedData().getMetaData().getPrefix();
var prefixComponent = PlainTextComponentSerializer.plainText().deserialize(prefix);
cache.put(playerId, prefixComponent);
}
@Override
public @Nullable Component getPrefix(UUID playerId) {
return cache.get(playerId);
}
}

View file

@ -1,13 +0,0 @@
package de.kentoj.scrow.bukkit.chatstyle;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class NoPrefixPrefixCache implements PrefixCache {
@Override
public @Nullable Component getPrefix(UUID playerId) {
return null;
}
}

View file

@ -1,11 +0,0 @@
package de.kentoj.scrow.bukkit.chatstyle;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public interface PrefixCache {
@Nullable Component getPrefix(UUID playerId);
}

View file

@ -1,4 +1,4 @@
package de.kentoj.scrow.bukkit.internal.network;
package de.kentoj.scrow.bukkit.internal.player;
import de.kentoj.scrow.bukkit.ScrowAPI;
import lombok.RequiredArgsConstructor;

View file

@ -0,0 +1,37 @@
package de.kentoj.scrow.bukkit.internal.player.prefix;
import de.kentoj.scrowlib.player.PlayerPrefixProvider;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;
import java.io.Closeable;
import java.util.*;
public class CachedPrefixProvider implements PlayerPrefixProvider {
private final Map<UUID, @Nullable Component> prefixes = new HashMap<>();
private final List<ChangeListener> listeners = new ArrayList<>();
@Override
public @Nullable Component getPrefix(UUID playerId) {
return prefixes.get(playerId);
}
@Override
public Closeable onChange(ChangeListener changeListener) {
listeners.add(changeListener);
return () -> listeners.remove(changeListener);
}
public void setPrefix(UUID playerId, @Nullable Component prefix) {
if (prefix == null) {
prefixes.remove(playerId);
} else {
var oldValue = prefixes.put(playerId, prefix);
var hasChanged = !Objects.equals(oldValue, prefix);
if (hasChanged) {
listeners.forEach(l -> l.onChange(playerId, prefix));
}
}
}
}

View file

@ -0,0 +1,65 @@
package de.kentoj.scrow.bukkit.internal.player.prefix;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.luckperms.api.LuckPerms;
import net.luckperms.api.event.user.UserDataRecalculateEvent;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.plugin.Plugin;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
@RequiredArgsConstructor
public class LuckPermsPrefixSetter implements Listener {
private static final MiniMessage MM = MiniMessage.miniMessage();
private final LuckPerms luckPerms;
private final CachedPrefixProvider cache;
@SuppressWarnings("resource")
public void init(Plugin plugin) {
luckPerms.getEventBus().subscribe(UserDataRecalculateEvent.class, this::onDataChange);
Bukkit.getPluginManager().registerEvents(this, plugin);
}
private void onDataChange(UserDataRecalculateEvent ev) {
var playerId = ev.getUser().getUniqueId();
if (Bukkit.getPlayer(playerId) == null) return;
var prefix = ev.getData().getMetaData().getPrefix();
updatePrefix(playerId, prefix);
}
@EventHandler(ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerJoin(PlayerJoinEvent ev) {
var playerId = ev.getPlayer().getUniqueId();
var user = luckPerms.getUserManager().getUser(playerId);
if (user == null) return;
var prefix = user.getCachedData().getMetaData().getPrefix();
updatePrefix(playerId, prefix);
}
@EventHandler
public void onPlayerQuit(PlayerQuitEvent ev) {
var playerId = ev.getPlayer().getUniqueId();
cache.setPrefix(playerId, (Component) null);
}
private void updatePrefix(UUID playerId, @Nullable String rawPrefix) {
if (rawPrefix == null) {
cache.setPrefix(playerId, (Component) null);
return;
}
var prefixComponent = MM.deserialize(rawPrefix);
cache.setPrefix(playerId, prefixComponent);
}
}

View file

@ -0,0 +1,23 @@
package de.kentoj.scrow.bukkit.style;
import de.kentoj.scrowlib.player.PlayerPrefixProvider;
import io.papermc.paper.event.player.AsyncChatEvent;
import lombok.RequiredArgsConstructor;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
@RequiredArgsConstructor
public class ChatStyleListener implements Listener {
private final PlayerPrefixProvider prefixProvider;
@EventHandler
public void onChat(AsyncChatEvent ev) {
var prefix = prefixProvider.getPrefix(ev.getPlayer().getUniqueId());
Component formattedMessage = StyleHelper.formatMessage(ev.getPlayer().name(), prefix, ev.message());
ev.setCancelled(true);
Bukkit.broadcast(formattedMessage);
}
}

View file

@ -0,0 +1,26 @@
package de.kentoj.scrow.bukkit.style;
import de.kentoj.scrowlib.utils.ComponentUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import org.jetbrains.annotations.Nullable;
@NoArgsConstructor(access = AccessLevel.NONE)
public class StyleHelper {
public static Component formatName(Component playerName, @Nullable Component prefix) {
Component result = prefix != null
? prefix.append(Component.text("").color(NamedTextColor.DARK_GRAY))
: Component.empty();
return result.append(playerName.color(NamedTextColor.GRAY));
}
public static Component formatMessage(Component playerName, @Nullable Component prefix, Component message) {
Component result = prefix != null
? prefix.append(Component.text("", NamedTextColor.DARK_GRAY))
: Component.empty();
return result.append(playerName.color(NamedTextColor.GRAY).append(Component.text(": ")))
.append(ComponentUtils.resolveURLS(message).colorIfAbsent(NamedTextColor.GRAY));
}
}

View file

@ -0,0 +1,37 @@
package de.kentoj.scrow.bukkit.style;
import de.kentoj.scrowlib.player.PlayerPrefixProvider;
import net.kyori.adventure.text.Component;
import org.bukkit.Bukkit;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class TabStyleListener implements Listener {
private final PlayerPrefixProvider prefixProvider;
public TabStyleListener(PlayerPrefixProvider prefixProvider) {
this.prefixProvider = prefixProvider;
//noinspection resource
prefixProvider.onChange(this::onPrefixChange);
}
private void onPrefixChange(UUID playerID, @Nullable Component prefix) {
var player = Bukkit.getPlayer(playerID);
if (player == null) return;
Component formattedName = StyleHelper.formatName(player.name(), prefix);
player.playerListName(formattedName);
}
@EventHandler(ignoreCancelled = true)
public void onPlayerJoin(PlayerJoinEvent ev) {
var prefix = prefixProvider.getPrefix(ev.getPlayer().getUniqueId());
Component formattedName = StyleHelper.formatName(ev.getPlayer().name(), prefix);
ev.getPlayer().playerListName(formattedName);
}
}