initial commit

This commit is contained in:
UrAvgCode 2025-09-09 23:50:59 +02:00
commit 574098a06a
No known key found for this signature in database
GPG key ID: 8A76A22B2CDDD634
21 changed files with 1924 additions and 0 deletions

View file

@ -0,0 +1,80 @@
package com.uravgcode.globalwhitelist;
import com.google.inject.Inject;
import com.uravgcode.globalwhitelist.command.WhitelistCommand;
import com.uravgcode.globalwhitelist.config.MessagesConfig;
import com.uravgcode.globalwhitelist.config.WhitelistConfig;
import com.uravgcode.globalwhitelist.service.MinecraftProfileService;
import com.uravgcode.globalwhitelist.whitelist.PlayerProfile;
import com.uravgcode.globalwhitelist.whitelist.Whitelist;
import com.velocitypowered.api.event.ResultedEvent;
import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.LoginEvent;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
import com.velocitypowered.api.plugin.Plugin;
import com.velocitypowered.api.plugin.annotation.DataDirectory;
import com.velocitypowered.api.proxy.ProxyServer;
import org.slf4j.Logger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@Plugin(
id = "global-whitelist",
name = "global-whitelist",
version = BuildConstants.VERSION,
url = "https://github.com/uravgcode/global-whitelist",
description = "velocity whitelist plugin",
authors = {"UrAvgCode"}
)
public class GlobalWhitelistPlugin {
private final ProxyServer proxy;
private final MinecraftProfileService profileService;
private final Whitelist whitelist;
private final WhitelistConfig config;
private final MessagesConfig messages;
@Inject
public GlobalWhitelistPlugin(ProxyServer server, Logger logger, @DataDirectory Path dataDirectory) {
this.proxy = server;
this.profileService = new MinecraftProfileService(logger);
this.whitelist = new Whitelist(dataDirectory.resolve("whitelist.json"), logger);
this.config = new WhitelistConfig(dataDirectory.resolve("config.properties"), logger);
this.messages = new MessagesConfig(dataDirectory.resolve("messages.properties"), logger);
try {
Files.createDirectories(dataDirectory);
} catch (IOException e) {
logger.error("failed to create plugin directory: {}", e.getMessage());
}
}
@Subscribe
public void onProxyInitialization(ProxyInitializeEvent event) {
config.reload();
whitelist.reload();
messages.reload();
proxy.getEventManager().register(this, LoginEvent.class, loginEvent -> {
if (!config.whitelistEnabled()) {
return;
}
var player = loginEvent.getPlayer();
if (!whitelist.contains(new PlayerProfile(player.getUniqueId(), player.getUsername()))) {
loginEvent.setResult(ResultedEvent.ComponentResult.denied(messages.getMessage(MessagesConfig.WHITELIST_REJECTED)));
}
});
var commandManager = proxy.getCommandManager();
var commandMeta = commandManager.metaBuilder("gwl")
.plugin(this)
.build();
var command = WhitelistCommand.createBrigadierCommand(proxy, profileService, whitelist, config, messages);
commandManager.register(commandMeta, command);
}
}

View file

@ -0,0 +1,94 @@
package com.uravgcode.globalwhitelist.command;
import com.mojang.brigadier.arguments.StringArgumentType;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import com.mojang.brigadier.tree.LiteralCommandNode;
import com.uravgcode.globalwhitelist.config.MessagesConfig;
import com.uravgcode.globalwhitelist.config.WhitelistConfig;
import com.uravgcode.globalwhitelist.service.MinecraftProfileService;
import com.uravgcode.globalwhitelist.whitelist.Whitelist;
import com.velocitypowered.api.command.BrigadierCommand;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.ProxyServer;
public final class WhitelistCommand {
private static final String PERMISSION_BASE = "globalwhitelist";
private static final String PERMISSION_ADMIN = "globalwhitelist.admin";
public static BrigadierCommand createBrigadierCommand(
final ProxyServer proxy,
final MinecraftProfileService profileService,
final Whitelist whitelist,
final WhitelistConfig config,
final MessagesConfig messages
) {
var commandHandler = new WhitelistCommandHandler(proxy, profileService, whitelist, config, messages);
LiteralCommandNode<CommandSource> helloNode = BrigadierCommand.literalArgumentBuilder("globalwhitelist")
.requires(source -> source.hasPermission(PERMISSION_BASE) || source.hasPermission(PERMISSION_ADMIN))
.executes(commandHandler::help)
.then(buildAddCommand(commandHandler))
.then(buildRemoveCommand(commandHandler))
.then(buildListCommand(commandHandler))
.then(buildReloadCommand(commandHandler))
.then(buildOnCommand(commandHandler))
.then(buildOffCommand(commandHandler))
.then(buildEnforcedCommand(commandHandler))
.then(buildUnenforcedCommand(commandHandler))
.build();
return new BrigadierCommand(helloNode);
}
private static LiteralArgumentBuilder<CommandSource> buildAddCommand(WhitelistCommandHandler handler) {
return BrigadierCommand.literalArgumentBuilder("add")
.requires(source -> source.hasPermission(PERMISSION_BASE))
.then(BrigadierCommand.requiredArgumentBuilder("player", StringArgumentType.word())
.suggests(handler::suggestOnlinePlayers)
.executes(handler::add));
}
private static LiteralArgumentBuilder<CommandSource> buildRemoveCommand(WhitelistCommandHandler handler) {
return BrigadierCommand.literalArgumentBuilder("remove")
.requires(source -> source.hasPermission(PERMISSION_BASE))
.then(BrigadierCommand.requiredArgumentBuilder("player", StringArgumentType.word())
.suggests(handler::suggestWhitelistedPlayers)
.executes(handler::remove));
}
private static LiteralArgumentBuilder<CommandSource> buildListCommand(WhitelistCommandHandler handler) {
return BrigadierCommand.literalArgumentBuilder("list")
.requires(source -> source.hasPermission(PERMISSION_BASE))
.executes(handler::list);
}
private static LiteralArgumentBuilder<CommandSource> buildOnCommand(WhitelistCommandHandler handler) {
return BrigadierCommand.literalArgumentBuilder("on")
.requires(source -> source.hasPermission(PERMISSION_ADMIN))
.executes(handler::on);
}
private static LiteralArgumentBuilder<CommandSource> buildOffCommand(WhitelistCommandHandler handler) {
return BrigadierCommand.literalArgumentBuilder("off")
.requires(source -> source.hasPermission(PERMISSION_ADMIN))
.executes(handler::off);
}
private static LiteralArgumentBuilder<CommandSource> buildEnforcedCommand(WhitelistCommandHandler handler) {
return BrigadierCommand.literalArgumentBuilder("enforced")
.requires(source -> source.hasPermission(PERMISSION_ADMIN))
.executes(handler::enforced);
}
private static LiteralArgumentBuilder<CommandSource> buildUnenforcedCommand(WhitelistCommandHandler handler) {
return BrigadierCommand.literalArgumentBuilder("unenforced")
.requires(source -> source.hasPermission(PERMISSION_ADMIN))
.executes(handler::unenforced);
}
private static LiteralArgumentBuilder<CommandSource> buildReloadCommand(WhitelistCommandHandler handler) {
return BrigadierCommand.literalArgumentBuilder("reload")
.requires(source -> source.hasPermission(PERMISSION_ADMIN))
.executes(handler::reload);
}
}

View file

@ -0,0 +1,174 @@
package com.uravgcode.globalwhitelist.command;
import com.mojang.brigadier.Command;
import com.mojang.brigadier.context.CommandContext;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.uravgcode.globalwhitelist.config.MessagesConfig;
import com.uravgcode.globalwhitelist.config.WhitelistConfig;
import com.uravgcode.globalwhitelist.service.MinecraftProfileService;
import com.uravgcode.globalwhitelist.whitelist.PlayerProfile;
import com.uravgcode.globalwhitelist.whitelist.Whitelist;
import com.velocitypowered.api.command.CommandSource;
import com.velocitypowered.api.proxy.ProxyServer;
import java.util.concurrent.CompletableFuture;
public class WhitelistCommandHandler {
private final ProxyServer proxy;
private final MinecraftProfileService profileService;
private final Whitelist whitelist;
private final WhitelistConfig config;
private final MessagesConfig messages;
public WhitelistCommandHandler(
final ProxyServer proxy,
final MinecraftProfileService profileService,
final Whitelist whitelist,
final WhitelistConfig config,
final MessagesConfig messages
) {
this.proxy = proxy;
this.profileService = profileService;
this.whitelist = whitelist;
this.config = config;
this.messages = messages;
}
public CompletableFuture<Suggestions> suggestOnlinePlayers(CommandContext<CommandSource> ignored, SuggestionsBuilder builder) {
proxy.getAllPlayers().forEach(player -> builder.suggest(player.getUsername()));
return builder.buildFuture();
}
public CompletableFuture<Suggestions> suggestWhitelistedPlayers(CommandContext<CommandSource> ignored, SuggestionsBuilder builder) {
whitelist.list().forEach(builder::suggest);
return builder.buildFuture();
}
public int help(CommandContext<CommandSource> context) {
context.getSource().sendMessage(messages.getMessage(MessagesConfig.WHITELIST_HELP));
return Command.SINGLE_SUCCESS;
}
public int add(CommandContext<CommandSource> context) {
var source = context.getSource();
var playerName = context.getArgument("player", String.class);
profileService.getProfile(playerName).ifPresentOrElse(player -> {
if (whitelist.add(player)) {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_ADD_SUCCESS, playerName));
} else {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_ADD_ALREADY_WHITELISTED, playerName));
}
}, () -> source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_PLAYER_DOES_NOT_EXIST, playerName)));
return Command.SINGLE_SUCCESS;
}
public int remove(CommandContext<CommandSource> context) {
var source = context.getSource();
var playerName = context.getArgument("player", String.class);
profileService.getProfile(playerName).ifPresentOrElse(player -> {
if (whitelist.remove(player)) {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_REMOVE_SUCCESS, playerName));
if (config.whitelistEnabled() && config.enforceWhitelistEnabled()) {
proxy.getPlayer(playerName).ifPresent(p -> p.disconnect(messages.getMessage(MessagesConfig.WHITELIST_REJECTED)));
}
} else {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_REMOVE_NOT_WHITELISTED, playerName));
}
}, () -> source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_PLAYER_DOES_NOT_EXIST, playerName)));
return Command.SINGLE_SUCCESS;
}
public int list(CommandContext<CommandSource> context) {
var source = context.getSource();
var playerList = whitelist.list();
if (playerList.isEmpty()) {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_LIST_EMPTY));
} else {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_LIST, playerList));
}
return Command.SINGLE_SUCCESS;
}
public int on(CommandContext<CommandSource> context) {
CommandSource source = context.getSource();
if (config.whitelistEnabled()) {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_ON_ALREADY));
} else {
config.setWhitelistEnabled(true);
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_ON));
if (config.enforceWhitelistEnabled()) {
for (var player : proxy.getAllPlayers()) {
if (!whitelist.contains(new PlayerProfile(player.getUniqueId(), player.getUsername()))) {
player.disconnect(messages.getMessage(MessagesConfig.WHITELIST_REJECTED));
}
}
}
}
return Command.SINGLE_SUCCESS;
}
public int off(CommandContext<CommandSource> context) {
CommandSource source = context.getSource();
if (config.whitelistEnabled()) {
config.setWhitelistEnabled(false);
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_OFF));
} else {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_OFF_ALREADY));
}
return Command.SINGLE_SUCCESS;
}
public int enforced(CommandContext<CommandSource> context) {
CommandSource source = context.getSource();
if (config.enforceWhitelistEnabled()) {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_ENFORCED_ALREADY));
} else {
config.setEnforceWhitelistEnabled(true);
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_ENFORCED));
if (config.whitelistEnabled()) {
for (var player : proxy.getAllPlayers()) {
if (!whitelist.contains(new PlayerProfile(player.getUniqueId(), player.getUsername()))) {
player.disconnect(messages.getMessage(MessagesConfig.WHITELIST_REJECTED));
}
}
}
}
return Command.SINGLE_SUCCESS;
}
public int unenforced(CommandContext<CommandSource> context) {
CommandSource source = context.getSource();
if (config.enforceWhitelistEnabled()) {
config.setEnforceWhitelistEnabled(false);
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_UNENFORCED));
} else {
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_UNENFORCED_ALREADY));
}
return Command.SINGLE_SUCCESS;
}
public int reload(CommandContext<CommandSource> context) {
whitelist.reload();
config.reload();
messages.reload();
CommandSource source = context.getSource();
source.sendMessage(messages.getMessage(MessagesConfig.WHITELIST_RELOAD));
return Command.SINGLE_SUCCESS;
}
}

View file

@ -0,0 +1,129 @@
package com.uravgcode.globalwhitelist.config;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.minimessage.tag.resolver.Placeholder;
import org.slf4j.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.List;
import java.util.Properties;
public class MessagesConfig {
public static final String WHITELIST_HELP = "whitelist.help";
public static final String WHITELIST_ADD_SUCCESS = "whitelist.add.success";
public static final String WHITELIST_ADD_ALREADY_WHITELISTED = "whitelist.add.already_whitelisted";
public static final String WHITELIST_REMOVE_SUCCESS = "whitelist.remove.success";
public static final String WHITELIST_REMOVE_NOT_WHITELISTED = "whitelist.remove.not_whitelisted";
public static final String WHITELIST_PLAYER_DOES_NOT_EXIST = "whitelist.player_does_not_exist";
public static final String WHITELIST_LIST = "whitelist.list";
public static final String WHITELIST_LIST_EMPTY = "whitelist.list.empty";
public static final String WHITELIST_ON = "whitelist.on";
public static final String WHITELIST_ON_ALREADY = "whitelist.on.already";
public static final String WHITELIST_OFF = "whitelist.off";
public static final String WHITELIST_OFF_ALREADY = "whitelist.off.already";
public static final String WHITELIST_ENFORCED = "whitelist.enforced";
public static final String WHITELIST_ENFORCED_ALREADY = "whitelist.enforced.already";
public static final String WHITELIST_UNENFORCED = "whitelist.unenforced";
public static final String WHITELIST_UNENFORCED_ALREADY = "whitelist.unenforced.already";
public static final String WHITELIST_RELOAD = "whitelist.reload";
public static final String WHITELIST_REJECTED = "whitelist.rejected";
private final Logger logger;
private final Properties messages;
private final File messagesFile;
private final MiniMessage miniMessage;
public MessagesConfig(
final Path messagesPath,
final Logger logger
) {
this.messagesFile = messagesPath.toFile();
this.logger = logger;
this.messages = new Properties();
this.miniMessage = MiniMessage.miniMessage();
}
public void reload() {
if (!messagesFile.exists()) {
loadDefaults();
save();
return;
}
try (FileInputStream in = new FileInputStream(messagesFile)) {
messages.load(in);
} catch (IOException e) {
logger.error("failed to load messages config: {}", e.getMessage());
}
}
public void save() {
try (FileOutputStream out = new FileOutputStream(messagesFile)) {
messages.store(out, "messages config");
} catch (IOException e) {
logger.error("failed to save messages config: {}", e.getMessage());
}
}
private void loadDefaults() {
messages.setProperty(WHITELIST_HELP, "<red>/globalwhitelist <add|remove|list|on|off|enforce|unenforce|reload>");
messages.setProperty(WHITELIST_ADD_SUCCESS, "Added <player> to the whitelist");
messages.setProperty(WHITELIST_ADD_ALREADY_WHITELISTED, "<red>Player is already whitelisted");
messages.setProperty(WHITELIST_REMOVE_SUCCESS, "Removed <player> from the whitelist");
messages.setProperty(WHITELIST_REMOVE_NOT_WHITELISTED, "<red>Player is not whitelisted");
messages.setProperty(WHITELIST_PLAYER_DOES_NOT_EXIST, "<red>That player does not exist");
messages.setProperty(WHITELIST_LIST, "There are <count> whitelisted player(s): <players>");
messages.setProperty(WHITELIST_LIST_EMPTY, "There are no whitelisted players");
messages.setProperty(WHITELIST_ON, "Whitelist is now turned on");
messages.setProperty(WHITELIST_ON_ALREADY, "<red>Whitelist is already turned on");
messages.setProperty(WHITELIST_OFF, "Whitelist is now turned off");
messages.setProperty(WHITELIST_OFF_ALREADY, "<red>Whitelist is already turned off");
messages.setProperty(WHITELIST_ENFORCED, "Enforce whitelist is now turned on");
messages.setProperty(WHITELIST_ENFORCED_ALREADY, "<red>Enforce whitelist is already turned on");
messages.setProperty(WHITELIST_UNENFORCED, "Enforce whitelist is now turned off");
messages.setProperty(WHITELIST_UNENFORCED_ALREADY, "<red>Enforce whitelist is already turned off");
messages.setProperty(WHITELIST_RELOAD, "Reloaded the whitelist");
messages.setProperty(WHITELIST_REJECTED, "<red>You are not whitelisted on this server!");
}
public String get(String key) {
return messages.getProperty(key, "");
}
public Component getMessage(String key) {
return miniMessage.deserialize(get(key));
}
public Component getMessage(String key, String player) {
return miniMessage.deserialize(get(key), Placeholder.component("player", Component.text(player)));
}
public Component getMessage(String key, List<String> players) {
return miniMessage.deserialize(
get(key),
Placeholder.component("count", Component.text(players.size())),
Placeholder.component("players", Component.text(String.join(", ", players)))
);
}
}

View file

@ -0,0 +1,66 @@
package com.uravgcode.globalwhitelist.config;
import org.slf4j.Logger;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Properties;
public class WhitelistConfig {
private static final String WHITE_LIST = "white-list";
private static final String ENFORCE_WHITELIST = "enforce-whitelist";
private final File configFile;
private final Logger logger;
private final Properties config;
public WhitelistConfig(Path configPath, Logger logger) {
this.configFile = configPath.toFile();
this.logger = logger;
this.config = new Properties();
}
public void reload() {
if (!configFile.exists()) {
config.setProperty(WHITE_LIST, "false");
config.setProperty(ENFORCE_WHITELIST, "false");
save();
return;
}
try (FileInputStream in = new FileInputStream(configFile)) {
config.load(in);
} catch (IOException e) {
logger.error("failed to load whitelist config: {}", e.getMessage());
}
}
public void save() {
try (FileOutputStream out = new FileOutputStream(configFile)) {
config.store(out, "whitelist config");
} catch (IOException e) {
logger.error("failed to save whitelist config: {}", e.getMessage());
}
}
public boolean whitelistEnabled() {
return Boolean.parseBoolean(config.getProperty(WHITE_LIST));
}
public void setWhitelistEnabled(boolean enabled) {
config.setProperty(WHITE_LIST, Boolean.toString(enabled));
save();
}
public boolean enforceWhitelistEnabled() {
return Boolean.parseBoolean(config.getProperty(ENFORCE_WHITELIST));
}
public void setEnforceWhitelistEnabled(boolean enabled) {
config.setProperty(ENFORCE_WHITELIST, Boolean.toString(enabled));
save();
}
}

View file

@ -0,0 +1,96 @@
package com.uravgcode.globalwhitelist.service;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.uravgcode.globalwhitelist.whitelist.PlayerProfile;
import org.slf4j.Logger;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Optional;
import java.util.UUID;
import java.util.regex.Pattern;
public class MinecraftProfileService {
private static final URI API_BASE_URL = URI.create("https://api.minecraftservices.com/minecraft/profile/lookup/name/");
private static final Pattern UUID_PATTERN = Pattern.compile("(\\p{XDigit}{8})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{4})(\\p{XDigit}{12})");
private static final Duration TIMEOUT = Duration.ofSeconds(5);
private final Logger logger;
private final HttpClient httpClient;
public MinecraftProfileService(Logger logger) {
this.logger = logger;
this.httpClient = HttpClient.newBuilder()
.connectTimeout(TIMEOUT)
.build();
}
public Optional<PlayerProfile> getProfile(String playerName) {
if (playerName == null || playerName.isBlank()) {
logger.warn("player name cannot be null or empty");
return Optional.empty();
}
try {
var request = HttpRequest.newBuilder()
.uri(API_BASE_URL.resolve(playerName))
.timeout(TIMEOUT)
.GET()
.build();
var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
return switch (response.statusCode()) {
case 200 -> parseProfile(response.body());
case 404 -> {
logger.warn("player with name {} not found", playerName);
yield Optional.empty();
}
default -> {
logger.warn("api request failed with status {}: {}", response.statusCode(), response.body());
yield Optional.empty();
}
};
} catch (IOException e) {
logger.error("network error while fetching profile for '{}': {}", playerName, e.getMessage());
return Optional.empty();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
logger.error("request interrupted while fetching profile for '{}': {}", playerName, e.getMessage());
return Optional.empty();
}
}
private Optional<PlayerProfile> parseProfile(String jsonString) {
try {
JsonObject jsonObject = JsonParser.parseString(jsonString).getAsJsonObject();
if (!jsonObject.has("id") || !jsonObject.has("name")) {
logger.warn("missing 'id' or 'name' in json:\n{}", jsonString);
return Optional.empty();
}
String uuidString = jsonObject.get("id").getAsString();
String name = jsonObject.get("name").getAsString();
var matcher = UUID_PATTERN.matcher(uuidString);
if (!matcher.matches()) {
logger.warn("invalid uuid format in json:\n{}", jsonString);
return Optional.empty();
}
var uuid = UUID.fromString(matcher.replaceFirst("$1-$2-$3-$4-$5"));
return Optional.of(new PlayerProfile(uuid, name));
} catch (Exception e) {
logger.error("failed to parse json:\n{}\nerror: {}", jsonString, e.getMessage());
return Optional.empty();
}
}
}

View file

@ -0,0 +1,17 @@
package com.uravgcode.globalwhitelist.whitelist;
import java.util.UUID;
public record PlayerProfile(UUID uuid, String name) {
@Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof PlayerProfile other)) return false;
return uuid.equals(other.uuid);
}
@Override
public int hashCode() {
return uuid.hashCode();
}
}

View file

@ -0,0 +1,84 @@
package com.uravgcode.globalwhitelist.whitelist;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import org.slf4j.Logger;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class Whitelist {
private final Logger logger;
private final File whitelistFile;
private final Set<PlayerProfile> whitelistPlayers;
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
public Whitelist(Path whitelistPath, Logger logger) {
this.logger = logger;
this.whitelistFile = whitelistPath.toFile();
this.whitelistPlayers = new HashSet<>();
}
public boolean contains(PlayerProfile player) {
return whitelistPlayers.contains(player);
}
public boolean add(PlayerProfile player) {
if (whitelistPlayers.add(player)) {
save();
return true;
}
return false;
}
public boolean remove(PlayerProfile player) {
if (whitelistPlayers.remove(player)) {
save();
return true;
}
return false;
}
public List<String> list() {
return whitelistPlayers.stream().map(PlayerProfile::name).toList();
}
public void reload() {
try {
if (whitelistFile.createNewFile()) {
whitelistPlayers.clear();
return;
}
try (FileReader reader = new FileReader(whitelistFile)) {
Type listType = new TypeToken<List<PlayerProfile>>() {
}.getType();
List<PlayerProfile> players = gson.fromJson(reader, listType);
if (players != null) {
whitelistPlayers.clear();
whitelistPlayers.addAll(players);
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void save() {
try (FileWriter writer = new FileWriter(whitelistFile)) {
gson.toJson(List.copyOf(whitelistPlayers), writer);
} catch (IOException e) {
logger.error("failed to save whitelist: {}", e.getMessage());
}
}
}

View file

@ -0,0 +1,5 @@
package com.uravgcode.globalwhitelist;
public class BuildConstants {
public static final String VERSION = "${version}";
}