feat: implemented player context management

This commit is contained in:
Andrey Terentev 2025-03-09 22:55:41 +07:00
parent 5253b89779
commit c6b6217588
6 changed files with 185 additions and 27 deletions

View File

@ -5,9 +5,13 @@ import lombok.experimental.UtilityClass;
import lombok.extern.log4j.Log4j2;
import net.kyori.adventure.key.Key;
import net.minestom.server.MinecraftServer;
import net.minestom.server.event.player.AsyncPlayerConfigurationEvent;
import net.minestom.server.event.player.PlayerDisconnectEvent;
import ru.dragonestia.msb3.api.entity.PickableItem;
import ru.dragonestia.msb3.api.item.ItemUtil;
import ru.dragonestia.msb3.api.player.MsbPlayer;
import ru.dragonestia.msb3.api.player.PlayerContextManager;
import ru.dragonestia.msb3.api.player.defaults.KeyedBossBarContext;
import ru.dragonestia.msb3.api.resource.DialogueResources;
import ru.dragonestia.msb3.api.resource.MonologueResources;
import ru.dragonestia.msb3.api.ui.BlackScreen;
@ -78,11 +82,7 @@ public final class ServerBootstrap {
compileResourcePack();
initializer.onResourcePackCompiled(Resources.getResourcePack());
MinecraftServer.getGlobalEventHandler().addListener(PlayerDisconnectEvent.class, event -> {
var player = event.getPlayer();
KeyedBossBars.hideAll(player);
});
initPlayerContextManager();
}
private void initDefaultModules() {
@ -153,4 +153,23 @@ public final class ServerBootstrap {
Resources.getResourcePack().language(Language.language(Key.key("minecraft", lang), locales));
}
}
private void initPlayerContextManager() {
MinecraftServer.getConnectionManager().setPlayerProvider(PlayerContextManager::create);
MinecraftServer.getGlobalEventHandler().addListener(AsyncPlayerConfigurationEvent.class, event -> {
var player = (MsbPlayer) event.getPlayer();
log.info("Connected player {} (uuid: {}, address: {})", player.getUsername(), player.getUuid(), player.getPlayerConnection().getRemoteAddress());
player.initContexts();
}).addListener(PlayerDisconnectEvent.class, event -> {
var player = (MsbPlayer) event.getPlayer();
log.info("Disconnected player {} (uuid: {}, address: {})", player.getUsername(), player.getUuid(), player.getPlayerConnection().getRemoteAddress());
player.disposeContexts();
});
// Default contexts
PlayerContextManager.registerContext(KeyedBossBarContext.class, KeyedBossBarContext::new);
}
}

View File

@ -0,0 +1,45 @@
package ru.dragonestia.msb3.api.player;
import net.minestom.server.entity.Player;
import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
public class MsbPlayer extends Player {
private final Map<String, PlayerContext> contexts = new HashMap<>();
public MsbPlayer(@NotNull PlayerConnection playerConnection, @NotNull GameProfile gameProfile) {
super(playerConnection, gameProfile);
}
void putContext(PlayerContext ctx) {
contexts.put(ctx.getClass().getName(), ctx);
}
@SuppressWarnings("unchecked")
public <T extends PlayerContext> T getContext(Class<T> clazz) {
return (T) contexts.get(clazz.getName());
}
public void initContexts() {
for (var entry: contexts.entrySet()) {
var ctxKey = entry.getKey();
var ctx = entry.getValue();
ctx.init();
}
}
public void disposeContexts() {
for (var entry: contexts.entrySet()) {
var ctxKey = entry.getKey();
var ctx = entry.getValue();
ctx.dispose();
}
}
}

View File

@ -0,0 +1,17 @@
package ru.dragonestia.msb3.api.player;
import lombok.Getter;
@Getter
public abstract class PlayerContext {
private final MsbPlayer player;
public PlayerContext(MsbPlayer player) {
this.player = player;
}
public abstract void init();
public abstract void dispose();
}

View File

@ -0,0 +1,45 @@
package ru.dragonestia.msb3.api.player;
import lombok.experimental.UtilityClass;
import lombok.extern.log4j.Log4j2;
import net.minestom.server.entity.Player;
import net.minestom.server.network.player.GameProfile;
import net.minestom.server.network.player.PlayerConnection;
import org.jetbrains.annotations.NotNull;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
@Log4j2
@UtilityClass
public class PlayerContextManager {
private final Map<String, Function<MsbPlayer, ? extends PlayerContext>> contexts = new HashMap<>();
public MsbPlayer create(@NotNull PlayerConnection playerConnection, @NotNull GameProfile gameProfile) {
var player = new MsbPlayer(playerConnection, gameProfile);
for (var entry: contexts.entrySet()) {
var ctxKey = entry.getKey();
var ctx = entry.getValue().apply(player);
player.putContext(ctx);
}
return player;
}
public void registerContext(Class<? extends PlayerContext> clazz, Function<MsbPlayer, ? extends PlayerContext> ctxProvider) {
var key = clazz.getName();
var prev = contexts.put(key, ctxProvider);
if (prev != null) {
log.warn("Duplicate context registration for {}", key);
}
}
public <T extends PlayerContext> T getContext(Player player, Class<T> clazz) {
return ((MsbPlayer) player).getContext(clazz);
}
}

View File

@ -0,0 +1,45 @@
package ru.dragonestia.msb3.api.player.defaults;
import net.kyori.adventure.bossbar.BossBar;
import ru.dragonestia.msb3.api.player.MsbPlayer;
import ru.dragonestia.msb3.api.player.PlayerContext;
import java.util.HashMap;
import java.util.Map;
public class KeyedBossBarContext extends PlayerContext {
private final Map<String, BossBar> bossBars = new HashMap<>();
public KeyedBossBarContext(MsbPlayer player) {
super(player);
}
@Override
public void init() {
}
@Override
public void dispose() {
hideAll();
}
public void hideAll() {
bossBars.forEach((barId, bossBar) -> getPlayer().hideBossBar(bossBar));
}
public void hide(String bossBarId) {
var bossBar = bossBars.remove(bossBarId);
if (bossBar == null) return;
getPlayer().hideBossBar(bossBar);
}
public BossBar show(String bossBarId, BossBar bossBar) {
var prev = bossBars.put(bossBarId, bossBar);
if (prev != null) getPlayer().hideBossBar(prev);
getPlayer().showBossBar(bossBar);
return bossBar;
}
}

View File

@ -5,13 +5,11 @@ import net.kyori.adventure.bossbar.BossBar;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import net.minestom.server.entity.Player;
import ru.dragonestia.msb3.api.player.PlayerContextManager;
import ru.dragonestia.msb3.api.player.defaults.KeyedBossBarContext;
import ru.dragonestia.msb3.api.util.ResourceFromJar;
import ru.dragonestia.msb3.resource.Resources;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
@UtilityClass
public class KeyedBossBars {
@ -24,34 +22,23 @@ public class KeyedBossBars {
ResourceFromJar.of("glyphs/navigator/notched_20_progress.png"));
}
private final Map<UUID, Map<String, BossBar>> bars = new ConcurrentHashMap<>();
public void hideAll(Player player) {
var map = bars.remove(player.getUuid());
if (map == null) return;
map.forEach((barId, bossBar) -> player.hideBossBar(bossBar));
contextOf(player).hideAll();
}
public void hide(Player player, String bossBarId) {
var map = bars.get(player.getUuid());
if (map == null) return;
var bossBar = map.remove(bossBarId);
if (bossBar == null) return;
player.hideBossBar(bossBar);
contextOf(player).hide(bossBarId);
}
public BossBar show(Player player, String bossBarId, BossBar bossBar) {
var playerBars = bars.computeIfAbsent(player.getUuid(), uuid -> new ConcurrentHashMap<>());
var prev = playerBars.put(bossBarId, bossBar);
if (prev != null) player.hideBossBar(prev);
player.showBossBar(bossBar);
return bossBar;
return contextOf(player).show(bossBarId, bossBar);
}
public BossBar showText(Player player, String bossBarId, Component text) {
return show(player, bossBarId, BossBar.bossBar(text, 1, BossBar.Color.WHITE, BossBar.Overlay.PROGRESS));
}
private KeyedBossBarContext contextOf(Player player) {
return PlayerContextManager.getContext(player, KeyedBossBarContext.class);
}
}