Merge pull request #339 from Protonull/player-name-cache

Create centralised player-name cache
This commit is contained in:
okx-code
2024-03-19 22:58:27 +00:00
committed by GitHub
4 changed files with 66 additions and 37 deletions

View File

@@ -18,6 +18,7 @@ import vg.civcraft.mc.civmodcore.inventory.items.EnchantUtils;
import vg.civcraft.mc.civmodcore.inventory.items.MoreTags;
import vg.civcraft.mc.civmodcore.inventory.items.SpawnEggUtils;
import vg.civcraft.mc.civmodcore.inventory.items.TreeTypeUtils;
import vg.civcraft.mc.civmodcore.players.PlayerNames;
import vg.civcraft.mc.civmodcore.players.scoreboard.bottom.BottomLineAPI;
import vg.civcraft.mc.civmodcore.players.scoreboard.side.ScoreBoardAPI;
import vg.civcraft.mc.civmodcore.players.scoreboard.side.ScoreBoardListener;
@@ -88,6 +89,7 @@ public class CivModCorePlugin extends ACivMod {
registerListener(DialogManager.INSTANCE);
registerListener(new ScoreBoardListener());
registerListener(new WorldTracker());
registerListener(new PlayerNames());
// Register commands
this.commands = new CommandManager(this);
this.commands.init();

View File

@@ -6,9 +6,11 @@ import co.aikar.commands.InvalidCommandArgument;
import java.util.Arrays;
import java.util.List;
import org.bukkit.Material;
import org.bukkit.OfflinePlayer;
import org.bukkit.command.ConsoleCommandSender;
import org.jetbrains.annotations.NotNull;
import vg.civcraft.mc.civmodcore.inventory.items.ItemUtils;
import vg.civcraft.mc.civmodcore.players.PlayerNames;
/**
* This is a separate helper class that allows plugins to use ACF without needing to commit to {@link CommandManager}
@@ -86,6 +88,22 @@ public final class CommandHelpers {
);
}
/**
* Completion for all known player names.
*/
public static void registerKnownPlayersCompletion(
final @NotNull CommandCompletions<?> completions
) {
completions.registerCompletion(
"allplayers",
(context) -> PlayerNames.getPlayerNames()
);
completions.setDefaultCompletion(
"allplayers",
OfflinePlayer.class
);
}
// ============================================================
// Contexts
// ============================================================

View File

@@ -10,25 +10,15 @@ import co.aikar.commands.CommandContexts;
import com.google.common.base.Strings;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.logging.Level;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.bukkit.plugin.Plugin;
import vg.civcraft.mc.civmodcore.utilities.CivLogger;
@@ -36,9 +26,6 @@ import vg.civcraft.mc.civmodcore.utilities.CivLogger;
* Command registration class wrapper around {@link BukkitCommandManager}.
*/
public class CommandManager extends BukkitCommandManager {
// Track players to offer quick completion where necessary.
private final Set<String> autocompletePlayerNames = new ConcurrentSkipListSet<>();
private final CivLogger logger;
/**
@@ -57,25 +44,6 @@ public class CommandManager extends BukkitCommandManager {
* {@link #unregisterCompletions()}, otherwise there may be issues.
*/
public final void init() {
// Prepare our list with player names on init.
// Load all known players once on initialization, then use a loginlistener to update the existing name set.
Arrays.stream(Bukkit.getOfflinePlayers()).map(OfflinePlayer::getName)
.filter(Objects::nonNull)
.forEach(autocompletePlayerNames::add);
/*TODO
this may be better solved with a single global listener, but the implications would've needed some checks.
This is pretty cheap and works fast.
*/
Bukkit.getPluginManager().registerEvents(new Listener() {
// Players joining should be added to our list, just in case they are new.
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onLogin(PlayerLoginEvent ev) {
// For autocomplete we wil update the listeners.
autocompletePlayerNames.add(ev.getPlayer().getName());
}
}, plugin);
registerContexts(getCommandContexts());
registerCompletions(getCommandCompletions());
registerCommands();
@@ -100,11 +68,7 @@ public class CommandManager extends BukkitCommandManager {
CommandHelpers.registerNoneCompletion(completions);
CommandHelpers.registerMaterialsCompletion(completions);
CommandHelpers.registerItemMaterialsCompletion(completions);
// Completion lists are copied so outer code can modify the lists without breaking our inner contracts,
// namely that all players should be searchable by completion.
// Using Collections.immutableList is an alternative, but both variants aren't expensive.
completions.registerAsyncCompletion("allplayers", (context) -> new ArrayList<>(autocompletePlayerNames));
CommandHelpers.registerKnownPlayersCompletion(completions);
}
/**

View File

@@ -0,0 +1,45 @@
package vg.civcraft.mc.civmodcore.players;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;
import org.apache.commons.lang3.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerLoginEvent;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
public final class PlayerNames implements Listener {
private static final Set<String> names = new HashSet<>();
public PlayerNames() {
names.clear();
names.addAll(
Stream.of(Bukkit.getOfflinePlayers())
.map(OfflinePlayer::getName)
.filter(StringUtils::isNotBlank)
.toList()
);
}
@EventHandler(
priority = EventPriority.MONITOR, // Make sure it happens after NameLayer's AssociationListener
ignoreCancelled = true
)
private void onLogin(
final @NotNull PlayerLoginEvent event
) {
names.add(event.getPlayer().getName());
}
public static @NotNull Collection<String> getPlayerNames() {
return Collections.unmodifiableSet(names);
}
}