1
0
mirror of https://github.com/GeyserMC/Floodgate.git synced 2025-12-19 14:59:20 +00:00

First part of news

This commit is contained in:
Tim203
2021-06-08 14:48:30 +02:00
parent 0773c7d37b
commit a65d4e821d
26 changed files with 517 additions and 86 deletions

View File

@@ -118,6 +118,12 @@ public interface PlayerLink {
@NonNull String code @NonNull String code
); );
/**
* Returns the name of this database implementation. This will return null when Player Linking
* is disabled or when <b>only</b> Global Linking is used.
*/
String getName();
/** /**
* Return if account linking is enabled. The difference between enabled and allowed is that * Return if account linking is enabled. The difference between enabled and allowed is that
* 'enabled' still allows already linked people to join with their linked account while 'allow * 'enabled' still allows already linked people to join with their linked account while 'allow

View File

@@ -28,6 +28,7 @@ package org.geysermc.floodgate.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -40,8 +41,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.player.UserAudienceArgument.PlayerType; import org.geysermc.floodgate.player.UserAudienceArgument.PlayerType;
import org.geysermc.floodgate.util.BungeeUserAudience.BungeeConsoleAudience; import org.geysermc.floodgate.util.BungeeUserAudience.BungeeConsoleAudience;
@@ -135,17 +136,40 @@ public final class BungeeCommandUtil implements CommandUtil {
} }
@Override @Override
public void sendMessage(Object target, String locale, CommandMessage message, Object... args) { public boolean hasPermission(Object player, String permission) {
return cast(player).hasPermission(permission);
}
@Override
public Collection<Object> getOnlinePlayersWithPermission(String permission) {
List<Object> players = new ArrayList<>();
for (ProxiedPlayer player : ProxyServer.getInstance().getPlayers()) {
if (hasPermission(player, permission)) {
players.add(player);
}
}
return players;
}
@Override
public void sendMessage(Object target, String locale, TranslatableMessage message, Object... args) {
((CommandSender) target).sendMessage(translateAndTransform(locale, message, args)); ((CommandSender) target).sendMessage(translateAndTransform(locale, message, args));
} }
@Override @Override
public void kickPlayer(Object player, String locale, CommandMessage message, Object... args) { public void sendMessage(Object target, String message) {
((CommandSender) target).sendMessage(message);
}
@Override
public void kickPlayer(Object player, String locale, TranslatableMessage message, Object... args) {
cast(player).disconnect(translateAndTransform(locale, message, args)); cast(player).disconnect(translateAndTransform(locale, message, args));
} }
public BaseComponent[] translateAndTransform(String locale, CommandMessage message, public BaseComponent[] translateAndTransform(
Object... args) { String locale,
TranslatableMessage message,
Object... args) {
return TextComponent.fromLegacyText(message.translateMessage(manager, locale, args)); return TextComponent.fromLegacyText(message.translateMessage(manager, locale, args));
} }

View File

@@ -37,8 +37,8 @@ import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.md_5.bungee.api.CommandSender; import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -74,13 +74,15 @@ public class BungeeUserAudience implements UserAudience, ForwardingAudience.Sing
} }
@Override @Override
public void sendMessage(@NonNull Identity source, @NonNull Component message, public void sendMessage(
@NonNull MessageType type) { @NonNull Identity source,
@NonNull Component message,
@NonNull MessageType type) {
this.source.sendMessage(GsonComponentSerializer.gson().serialize(message)); this.source.sendMessage(GsonComponentSerializer.gson().serialize(message));
} }
@Override @Override
public void sendMessage(CommandMessage message, Object... args) { public void sendMessage(TranslatableMessage message, Object... args) {
commandUtil.sendMessage(source(), locale(), message, args); commandUtil.sendMessage(source(), locale(), message, args);
} }
@@ -92,7 +94,7 @@ public class BungeeUserAudience implements UserAudience, ForwardingAudience.Sing
} }
@Override @Override
public void disconnect(CommandMessage message, Object... args) { public void disconnect(TranslatableMessage message, Object... args) {
commandUtil.kickPlayer(source(), locale(), message, args); commandUtil.kickPlayer(source(), locale(), message, args);
} }

View File

@@ -46,6 +46,7 @@ import org.geysermc.floodgate.config.loader.ConfigLoader;
import org.geysermc.floodgate.link.PlayerLinkLoader; import org.geysermc.floodgate.link.PlayerLinkLoader;
import org.geysermc.floodgate.module.ConfigLoadedModule; import org.geysermc.floodgate.module.ConfigLoadedModule;
import org.geysermc.floodgate.module.PostInitializeModule; import org.geysermc.floodgate.module.PostInitializeModule;
import org.geysermc.floodgate.news.NewsChecker;
import org.geysermc.floodgate.util.PrefixCheckTask; import org.geysermc.floodgate.util.PrefixCheckTask;
import org.geysermc.floodgate.util.TimeSyncerHolder; import org.geysermc.floodgate.util.TimeSyncerHolder;
@@ -123,6 +124,7 @@ public class FloodgatePlatform {
PrefixCheckTask.checkAndExecuteDelayed(config, logger); PrefixCheckTask.checkAndExecuteDelayed(config, logger);
guice.getInstance(NewsChecker.class).start();
return true; return true;
} }

View File

@@ -28,7 +28,7 @@ package org.geysermc.floodgate.addon.debug;
public enum State { public enum State {
HANDSHAKE, STATUS, LOGIN, PLAY; HANDSHAKE, STATUS, LOGIN, PLAY;
public static final State[] VALUES = values(); private static final State[] VALUES = values();
public static State getById(int id) { public static State getById(int id) {
return id < VALUES.length ? VALUES[id] : null; return id < VALUES.length ? VALUES[id] : null;

View File

@@ -26,14 +26,14 @@
package org.geysermc.floodgate.command; package org.geysermc.floodgate.command;
import lombok.Getter; import lombok.Getter;
import org.geysermc.floodgate.platform.command.CommandMessage; import org.geysermc.floodgate.platform.command.TranslatableMessage;
/** /**
* Messages (or part of messages) that are used in two or more commands and thus are 'commonly * Messages (or part of messages) that are used in two or more commands and thus are 'commonly
* used' * used'
*/ */
@Getter @Getter
public enum CommonCommandMessage implements CommandMessage { public enum CommonCommandMessage implements TranslatableMessage {
LINKING_DISABLED("floodgate.commands.linking_disabled"), LINKING_DISABLED("floodgate.commands.linking_disabled"),
NOT_A_PLAYER("floodgate.commands.not_a_player"), NOT_A_PLAYER("floodgate.commands.not_a_player"),
CHECK_CONSOLE("floodgate.commands.check_console"), CHECK_CONSOLE("floodgate.commands.check_console"),

View File

@@ -42,12 +42,13 @@ import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.link.GlobalPlayerLinking; import org.geysermc.floodgate.link.GlobalPlayerLinking;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.platform.command.FloodgateCommand;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.player.UserAudience.PlayerAudience; import org.geysermc.floodgate.player.UserAudience.PlayerAudience;
import org.geysermc.floodgate.player.UserAudienceArgument; import org.geysermc.floodgate.player.UserAudienceArgument;
import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.Permissions;
@NoArgsConstructor @NoArgsConstructor
public final class LinkAccountCommand implements FloodgateCommand { public final class LinkAccountCommand implements FloodgateCommand {
@@ -59,7 +60,7 @@ public final class LinkAccountCommand implements FloodgateCommand {
return commandManager.commandBuilder("linkaccount", return commandManager.commandBuilder("linkaccount",
ArgumentDescription.of("Link your Java account with your Bedrock account")) ArgumentDescription.of("Link your Java account with your Bedrock account"))
.senderType(PlayerAudience.class) .senderType(PlayerAudience.class)
.permission("floodgate.command.linkaccount") .permission(Permissions.COMMAND_LINK.get())
.argument(UserAudienceArgument.of("player", true)) .argument(UserAudienceArgument.of("player", true))
.argument(StringArgument.optional("code")) .argument(StringArgument.optional("code"))
.handler(this::execute) .handler(this::execute)
@@ -165,7 +166,7 @@ public final class LinkAccountCommand implements FloodgateCommand {
} }
@Getter @Getter
public enum Message implements CommandMessage { public enum Message implements TranslatableMessage {
ALREADY_LINKED("floodgate.command.link_account.already_linked"), ALREADY_LINKED("floodgate.command.link_account.already_linked"),
JAVA_USAGE("floodgate.command.link_account.java_usage"), JAVA_USAGE("floodgate.command.link_account.java_usage"),
LINK_REQUEST_CREATED("floodgate.command.link_account.link_request_created"), LINK_REQUEST_CREATED("floodgate.command.link_account.link_request_created"),

View File

@@ -38,11 +38,12 @@ import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.link.GlobalPlayerLinking; import org.geysermc.floodgate.link.GlobalPlayerLinking;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.platform.command.FloodgateCommand;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.player.UserAudience.PlayerAudience; import org.geysermc.floodgate.player.UserAudience.PlayerAudience;
import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.Permissions;
@NoArgsConstructor @NoArgsConstructor
public final class UnlinkAccountCommand implements FloodgateCommand { public final class UnlinkAccountCommand implements FloodgateCommand {
@@ -53,7 +54,7 @@ public final class UnlinkAccountCommand implements FloodgateCommand {
return commandManager.commandBuilder("unlinkaccount", return commandManager.commandBuilder("unlinkaccount",
ArgumentDescription.of("Unlink your Java account from your Bedrock account")) ArgumentDescription.of("Unlink your Java account from your Bedrock account"))
.senderType(PlayerAudience.class) .senderType(PlayerAudience.class)
.permission("floodgate.command.unlinkaccount") .permission(Permissions.COMMAND_UNLINK.get())
.handler(this::execute) .handler(this::execute)
.build(); .build();
} }
@@ -113,7 +114,7 @@ public final class UnlinkAccountCommand implements FloodgateCommand {
} }
@Getter @Getter
public enum Message implements CommandMessage { public enum Message implements TranslatableMessage {
NOT_LINKED("floodgate.command.unlink_account.not_linked"), NOT_LINKED("floodgate.command.unlink_account.not_linked"),
UNLINK_SUCCESS("floodgate.command.unlink_account.unlink_success"), UNLINK_SUCCESS("floodgate.command.unlink_account.unlink_success"),
UNLINK_ERROR("floodgate.command.unlink_account.error " + CHECK_CONSOLE); UNLINK_ERROR("floodgate.command.unlink_account.error " + CHECK_CONSOLE);

View File

@@ -37,13 +37,14 @@ import lombok.Getter;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.config.FloodgateConfig; import org.geysermc.floodgate.config.FloodgateConfig;
import org.geysermc.floodgate.config.ProxyFloodgateConfig; import org.geysermc.floodgate.config.ProxyFloodgateConfig;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.command.FloodgateCommand; import org.geysermc.floodgate.platform.command.FloodgateCommand;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.player.UserAudienceArgument; import org.geysermc.floodgate.player.UserAudienceArgument;
import org.geysermc.floodgate.util.Constants; import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpUtils; import org.geysermc.floodgate.util.HttpUtils;
import org.geysermc.floodgate.util.Permissions;
public class WhitelistCommand implements FloodgateCommand { public class WhitelistCommand implements FloodgateCommand {
@Inject private FloodgateConfig config; @Inject private FloodgateConfig config;
@@ -53,7 +54,7 @@ public class WhitelistCommand implements FloodgateCommand {
public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) { public Command<UserAudience> buildCommand(CommandManager<UserAudience> commandManager) {
Command.Builder<UserAudience> builder = commandManager.commandBuilder("fwhitelist", Command.Builder<UserAudience> builder = commandManager.commandBuilder("fwhitelist",
ArgumentDescription.of("Easy way to whitelist Bedrock players")) ArgumentDescription.of("Easy way to whitelist Bedrock players"))
.permission("floodgate.command.fwhitelist"); .permission(Permissions.COMMAND_WHITELIST.get());
commandManager.command(builder commandManager.command(builder
.literal("add", "a") .literal("add", "a")
@@ -153,7 +154,7 @@ public class WhitelistCommand implements FloodgateCommand {
} }
@Getter @Getter
public enum Message implements CommandMessage { public enum Message implements TranslatableMessage {
INVALID_USERNAME("floodgate.command.fwhitelist.invalid_username"), INVALID_USERNAME("floodgate.command.fwhitelist.invalid_username"),
API_UNAVAILABLE("floodgate.command.fwhitelist.api_unavailable " + CHECK_CONSOLE), API_UNAVAILABLE("floodgate.command.fwhitelist.api_unavailable " + CHECK_CONSOLE),
USER_NOT_FOUND("floodgate.command.fwhitelist.user_not_found"), USER_NOT_FOUND("floodgate.command.fwhitelist.user_not_found"),

View File

@@ -26,6 +26,8 @@
package org.geysermc.floodgate.link; package org.geysermc.floodgate.link;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.name.Names;
import java.util.Random; import java.util.Random;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
@@ -91,6 +93,11 @@ public abstract class CommonPlayerLink implements PlayerLink {
return injectorHolder.get().getInstance(DatabaseConfigLoader.class).loadAs(configClass); return injectorHolder.get().getInstance(DatabaseConfigLoader.class).loadAs(configClass);
} }
@Override
public String getName() {
return injectorHolder.get().getInstance(Key.get(String.class, Names.named("databaseName")));
}
@Override @Override
public void stop() { public void stop() {
executorService.shutdown(); executorService.shutdown();

View File

@@ -90,6 +90,11 @@ final class DisabledPlayerLink implements PlayerLink {
return failedFuture(); return failedFuture();
} }
@Override
public String getName() {
return null;
}
@Override @Override
public boolean isEnabled() { public boolean isEnabled() {
return false; return false;

View File

@@ -33,7 +33,7 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.api.link.LinkRequestResult; import org.geysermc.floodgate.api.link.LinkRequestResult;
import org.geysermc.floodgate.api.link.PlayerLink; import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.util.HttpUtils; import org.geysermc.floodgate.util.HttpUtils;
import org.geysermc.floodgate.util.HttpUtils.HttpResponse; import org.geysermc.floodgate.util.HttpUtils.DefaultHttpResponse;
import org.geysermc.floodgate.util.LinkedPlayer; import org.geysermc.floodgate.util.LinkedPlayer;
import org.geysermc.floodgate.util.Utils; import org.geysermc.floodgate.util.Utils;
@@ -55,6 +55,15 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
} }
} }
@Override
public String getName() {
if (databaseImpl != null) {
return databaseImpl.getName();
}
// Global Linking is integrated
return null;
}
@Override @Override
public void stop() { public void stop() {
super.stop(); super.stop();
@@ -82,7 +91,7 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
private CompletableFuture<LinkedPlayer> getLinkedPlayer0(@NonNull UUID bedrockId) { private CompletableFuture<LinkedPlayer> getLinkedPlayer0(@NonNull UUID bedrockId) {
return CompletableFuture.supplyAsync( return CompletableFuture.supplyAsync(
() -> { () -> {
HttpResponse response = DefaultHttpResponse response =
HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits()); HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
// both on code != 200 and fails with 200 'success' will be false // both on code != 200 and fails with 200 'success' will be false
@@ -128,7 +137,7 @@ public class GlobalPlayerLinking extends CommonPlayerLink {
private CompletableFuture<Boolean> isLinkedPlayer0(@NonNull UUID bedrockId) { private CompletableFuture<Boolean> isLinkedPlayer0(@NonNull UUID bedrockId) {
return CompletableFuture.supplyAsync( return CompletableFuture.supplyAsync(
() -> { () -> {
HttpResponse response = DefaultHttpResponse response =
HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits()); HttpUtils.get(GET_BEDROCK_LINK + bedrockId.getLeastSignificantBits());
// both on http != 200 and fails with 200 success will be false // both on http != 200 and fails with 200 success will be false

View File

@@ -34,9 +34,11 @@ import java.nio.file.Path;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl; import org.geysermc.floodgate.addon.data.HandshakeHandlersImpl;
import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.InstanceHolder;
import org.geysermc.floodgate.api.SimpleFloodgateApi; import org.geysermc.floodgate.api.SimpleFloodgateApi;
import org.geysermc.floodgate.api.handshake.HandshakeHandlers; import org.geysermc.floodgate.api.handshake.HandshakeHandlers;
import org.geysermc.floodgate.api.inject.PlatformInjector; import org.geysermc.floodgate.api.inject.PlatformInjector;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.api.packet.PacketHandlers; import org.geysermc.floodgate.api.packet.PacketHandlers;
import org.geysermc.floodgate.api.player.FloodgatePlayer; import org.geysermc.floodgate.api.player.FloodgatePlayer;
@@ -52,7 +54,9 @@ import org.geysermc.floodgate.crypto.Base64Topping;
import org.geysermc.floodgate.crypto.FloodgateCipher; import org.geysermc.floodgate.crypto.FloodgateCipher;
import org.geysermc.floodgate.crypto.KeyProducer; import org.geysermc.floodgate.crypto.KeyProducer;
import org.geysermc.floodgate.inject.CommonPlatformInjector; import org.geysermc.floodgate.inject.CommonPlatformInjector;
import org.geysermc.floodgate.news.NewsChecker;
import org.geysermc.floodgate.packet.PacketHandlersImpl; import org.geysermc.floodgate.packet.PacketHandlersImpl;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.player.FloodgateHandshakeHandler; import org.geysermc.floodgate.player.FloodgateHandshakeHandler;
import org.geysermc.floodgate.pluginmessage.PluginMessageManager; import org.geysermc.floodgate.pluginmessage.PluginMessageManager;
import org.geysermc.floodgate.skin.SkinApplier; import org.geysermc.floodgate.skin.SkinApplier;
@@ -169,6 +173,15 @@ public class CommonModule extends AbstractModule {
return new SkinUploadManager(api, skinApplier, logger); return new SkinUploadManager(api, skinApplier, logger);
} }
@Provides
@Singleton
public NewsChecker newsChecker(CommandUtil commandUtil, FloodgateLogger logger) {
// will be loaded after enabling, so we can use the link instance in InstanceHolder
PlayerLink link = InstanceHolder.getPlayerLink();
logger.info(link.getName());
return new NewsChecker(link, commandUtil, logger, null, -1);
}
@Provides @Provides
@Singleton @Singleton
@Named("kickMessageAttribute") @Named("kickMessageAttribute")

View File

@@ -0,0 +1,208 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.news;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.geysermc.floodgate.api.link.PlayerLink;
import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.news.data.BuildSpecificData;
import org.geysermc.floodgate.news.data.CheckAfterData;
import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.util.Constants;
import org.geysermc.floodgate.util.HttpUtils;
import org.geysermc.floodgate.util.HttpUtils.HttpResponse;
import org.geysermc.floodgate.util.Permissions;
public class NewsChecker {
private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1);
private final PlayerLink link;
private final CommandUtil commandUtil;
private final FloodgateLogger logger;
private final Map<Integer, NewsItem> activeNewsItems = new HashMap<>();
private final String branch;
private final int build;
private boolean firstCheck;
public NewsChecker(
PlayerLink link,
CommandUtil commandUtil,
FloodgateLogger logger,
String branch,
int build) {
this.link = link;
this.commandUtil = commandUtil;
this.logger = logger;
this.branch = branch;
this.build = build;
}
public void start() {
executorService.scheduleWithFixedDelay(this::checkNews, 0, 30, TimeUnit.MINUTES);
}
private void schedule(long delayMs) {
executorService.schedule(this::checkNews, delayMs, TimeUnit.MILLISECONDS);
}
private void checkNews() {
HttpResponse<JsonArray> response =
HttpUtils.getSilent(Constants.NEWS_OVERVIEW_URL, JsonArray.class);
JsonArray array = response.getResponse();
// silent mode doesn't throw exceptions, so array will be null on failure
if (array == null) {
return;
}
try {
for (JsonElement newsItemElement : array) {
NewsItem newsItem = NewsItem.readItem(newsItemElement.getAsJsonObject());
if (newsItem != null) {
addNews(newsItem);
}
}
firstCheck = false;
} catch (Exception e) {
if (logger.isDebug()) {
logger.error("Error while reading news item", e);
}
}
}
public void handleNews(Object player, NewsItemAction action) {
for (NewsItem news : getActiveNews(action)) {
handleNewsItem(player, news, action);
}
}
private void handleNewsItem(Object player, NewsItem news, NewsItemAction action) {
switch (action) {
case ON_SERVER_STARTED:
if (!firstCheck) {
return;
}
case BROADCAST_TO_CONSOLE:
logger.info(news.getMessage());
break;
case ON_OPERATOR_JOIN:
if (player == null) {
return;
}
if (commandUtil.hasPermission(player, Permissions.NEWS_RECEIVE.get())) {
String message = Constants.COLOR_CHAR + "a " + news.getMessage();
commandUtil.sendMessage(player, message);
}
break;
case BROADCAST_TO_OPERATORS:
Collection<Object> onlinePlayers = commandUtil.getOnlinePlayersWithPermission(
Permissions.NEWS_RECEIVE.get()
);
for (Object onlinePlayer : onlinePlayers) {
String message = Constants.COLOR_CHAR + "a " + news.getMessage();
commandUtil.sendMessage(onlinePlayer, message);
}
break;
}
}
public Collection<NewsItem> getActiveNews() {
return activeNewsItems.values();
}
public Collection<NewsItem> getActiveNews(NewsItemAction action) {
List<NewsItem> news = new ArrayList<>();
for (NewsItem item : getActiveNews()) {
if (item.getActions().contains(action)) {
news.add(item);
}
}
return news;
}
public void addNews(NewsItem item) {
if (activeNewsItems.containsKey(item.getId())) {
if (!item.isActive()) {
activeNewsItems.remove(item.getId());
}
return;
}
if (!item.isActive()) {
return;
}
if (!item.isGlobal() && !Constants.NEWS_PROJECT_NAME.equals(item.getProject())) {
// only non-integrated database types have a name
if (link.getName() == null) {
return;
}
String fullDatabaseName = Constants.NEWS_PROJECT_NAME + link.getName();
if (!fullDatabaseName.equals(item.getProject())) {
return;
}
}
switch (item.getType()) {
case BUILD_SPECIFIC:
if (!item.getDataAs(BuildSpecificData.class).isAffected(branch, build)) {
return;
}
break;
case CHECK_AFTER:
long checkAfter = item.getDataAs(CheckAfterData.class).getCheckAfter();
long delayMs = System.currentTimeMillis() - checkAfter;
schedule(delayMs > 0 ? delayMs : 0);
break;
}
activeNewsItems.put(item.getId(), item);
activateNews(item);
}
private void activateNews(NewsItem item) {
for (NewsItemAction action : item.getActions()) {
handleNewsItem(null, item, action);
}
}
public void shutdown() {
executorService.shutdown();
}
}

View File

@@ -50,25 +50,51 @@ public interface CommandUtil {
@NonNull Collection<String> getOnlineUsernames(final @NonNull PlayerType limitTo); @NonNull Collection<String> getOnlineUsernames(final @NonNull PlayerType limitTo);
/** /**
* Send a message to the specified target, no matter what platform Floodgate is running on. * Checks if the given player has the given permission.
* *
* @param target the target to send the message to * @param player the player to check
* @param message the command message * @param permission the permission to check
* @param locale the locale of the player * @return true or false depending on if the player has the permission
* @param args the arguments
*/ */
void sendMessage(Object target, String locale, CommandMessage message, Object... args); boolean hasPermission(Object player, String permission);
/** /**
* Same as {@link CommandUtil#sendMessage(Object, String, CommandMessage, Object...)} except it * Get all online players with the given permission.
* kicks the player.
* *
* @param player the player to send the message to * @param permission the permission to check
* @return a list of online players that have the given permission
*/
Collection<Object> getOnlinePlayersWithPermission(String permission);
/**
* Send a message to the specified target, no matter what platform Floodgate is running on.
*
* @param target the player that should receive the message
* @param message the command message * @param message the command message
* @param locale the locale of the player * @param locale the locale of the player
* @param args the arguments * @param args the arguments
*/ */
void kickPlayer(Object player, String locale, CommandMessage message, Object... args); void sendMessage(Object target, String locale, TranslatableMessage message, Object... args);
/**
* Sends a raw message to the specified target, no matter what platform Floodgate is running
* on.
*
* @param target the player that should receive the message
* @param message the message
*/
void sendMessage(Object target, String message);
/**
* Same as {@link CommandUtil#sendMessage(Object, String, TranslatableMessage, Object...)}
* except it kicks the player using the given message as the kick reason.
*
* @param player the player that should be kicked
* @param message the command message
* @param locale the locale of the player
* @param args the arguments
*/
void kickPlayer(Object player, String locale, TranslatableMessage message, Object... args);
/** /**
* Whitelist the given Bedrock player. * Whitelist the given Bedrock player.

View File

@@ -28,10 +28,10 @@ package org.geysermc.floodgate.platform.command;
import org.geysermc.floodgate.util.LanguageManager; import org.geysermc.floodgate.util.LanguageManager;
/** /**
* CommandMessage is the interface of a message that can be send to a command source after executing * TranslatableMessage is the interface for a message that can be translated.
* a command. Messages are generally implemented using enums. * Messages are generally implemented using enums.
*/ */
public interface CommandMessage { public interface TranslatableMessage {
/** /**
* Returns the message attached to the enum identifier * Returns the message attached to the enum identifier
*/ */

View File

@@ -26,8 +26,8 @@
package org.geysermc.floodgate.platform.util; package org.geysermc.floodgate.platform.util;
import java.util.Collection; import java.util.Collection;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
public interface PlatformUtils { public interface PlatformUtils {
/** /**
@@ -38,10 +38,10 @@ public interface PlatformUtils {
* @param locale the locale of the player * @param locale the locale of the player
* @param args the arguments * @param args the arguments
*/ */
void sendMessage(Object player, String locale, CommandMessage message, Object... args); void sendMessage(Object player, String locale, TranslatableMessage message, Object... args);
/** /**
* Same as {@link CommandUtil#sendMessage(Object, String, CommandMessage, Object...)} except it * Same as {@link CommandUtil#sendMessage(Object, String, TranslatableMessage, Object...)} except it
* kicks the player. * kicks the player.
* *
* @param player the player to send the message to * @param player the player to send the message to
@@ -49,7 +49,7 @@ public interface PlatformUtils {
* @param locale the locale of the player * @param locale the locale of the player
* @param args the arguments * @param args the arguments
*/ */
void kickPlayer(Object player, String locale, CommandMessage message, Object... args); void kickPlayer(Object player, String locale, TranslatableMessage message, Object... args);
Collection<String> getOnlineUsernames(PlayerType limitTo); Collection<String> getOnlineUsernames(PlayerType limitTo);

View File

@@ -32,7 +32,7 @@ import net.kyori.adventure.identity.Identified;
import net.kyori.adventure.identity.Identity; import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.platform.command.CommandMessage; import org.geysermc.floodgate.platform.command.TranslatableMessage;
public interface UserAudience extends Identified, Identity, Audience { public interface UserAudience extends Identified, Identity, Audience {
@Override @Override
@@ -51,11 +51,11 @@ public interface UserAudience extends Identified, Identity, Audience {
final @NonNull Component message, final @NonNull Component message,
final @NonNull MessageType type); final @NonNull MessageType type);
void sendMessage(CommandMessage message, Object... args); void sendMessage(TranslatableMessage message, Object... args);
void disconnect(@NonNull final Component reason); void disconnect(@NonNull final Component reason);
void disconnect(CommandMessage message, Object... args); void disconnect(TranslatableMessage message, Object... args);
@Override @Override
default @NonNull Identity identity() { default @NonNull Identity identity() {

View File

@@ -26,6 +26,8 @@
package org.geysermc.floodgate.util; package org.geysermc.floodgate.util;
public final class Constants { public final class Constants {
public static final char COLOR_CHAR = '§';
public static final boolean DEBUG_MODE = true; public static final boolean DEBUG_MODE = true;
public static final boolean PRINT_ALL_PACKETS = false; public static final boolean PRINT_ALL_PACKETS = false;
@@ -36,9 +38,12 @@ public final class Constants {
public static final String WEBSOCKET_URL = "ws" + API_BASE_URL + "/ws"; public static final String WEBSOCKET_URL = "ws" + API_BASE_URL + "/ws";
public static final String GET_XUID_URL = "http" + API_BASE_URL + "/v1/xbox/xuid/"; public static final String GET_XUID_URL = "http" + API_BASE_URL + "/v1/xbox/xuid/";
public static final String GET_GAMERTAG_URL = "http" + API_BASE_URL + "/v1/xbox/gamertag/"; public static final String GET_GAMERTAG_URL = "http" + API_BASE_URL + "/v1/xbox/gamertag/";
public static final String NEWS_OVERVIEW_URL = "http" + API_BASE_URL + "/v1/news";
public static final String LINK_INFO_URL = "https://link.geysermc.org/"; public static final String LINK_INFO_URL = "https://link.geysermc.org/";
public static final String NEWS_PROJECT_NAME = "floodgate";
public static final String NTP_SERVER = "time.cloudflare.com"; public static final String NTP_SERVER = "time.cloudflare.com";
public static final String TIMESTAMP_DENIED_MESSAGE = public static final String TIMESTAMP_DENIED_MESSAGE =

View File

@@ -48,13 +48,21 @@ public class HttpUtils {
private static final String BOUNDARY = "******"; private static final String BOUNDARY = "******";
private static final String END = "\r\n"; private static final String END = "\r\n";
public static CompletableFuture<HttpResponse> asyncGet(String urlString) { public static CompletableFuture<DefaultHttpResponse> asyncGet(String urlString) {
return CompletableFuture.supplyAsync(() -> { return CompletableFuture.supplyAsync(() -> {
return get(urlString); return get(urlString);
}, EXECUTOR_SERVICE); }, EXECUTOR_SERVICE);
} }
public static HttpResponse get(String urlString) { public static DefaultHttpResponse get(String urlString) {
return readDefaultResponse(request(urlString));
}
public static <T> HttpResponse<T> getSilent(String urlString, Class<T> clazz) {
return readResponseSilent(request(urlString), clazz);
}
private static HttpURLConnection request(String urlString) {
HttpURLConnection connection; HttpURLConnection connection;
try { try {
@@ -68,34 +76,37 @@ public class HttpUtils {
connection.setRequestMethod("GET"); connection.setRequestMethod("GET");
connection.setUseCaches(false); connection.setUseCaches(false);
connection.setRequestProperty("User-Agent", USER_AGENT); connection.setRequestProperty("User-Agent", USER_AGENT);
connection.setRequestProperty("ContentType", "application/json");
} catch (Exception exception) { } catch (Exception exception) {
throw new RuntimeException("Failed to create request", exception); throw new RuntimeException("Failed to create request", exception);
} }
return readResponse(connection); return connection;
} }
private static HttpResponse readResponse(HttpURLConnection connection) { private static <T> HttpResponse<T> readResponseSilent(HttpURLConnection connection, Class<T> clazz) {
InputStream stream = null; InputStreamReader streamReader = createReader(connection);
try {
stream = connection.getInputStream();
} catch (Exception exception) {
try {
stream = connection.getErrorStream();
} catch (Exception exception1) {
throw new RuntimeException("Both the input and the error stream failed?!");
}
}
InputStreamReader streamReader = new InputStreamReader(stream);
try { try {
int responseCode = connection.getResponseCode(); int responseCode = connection.getResponseCode();
T response = GSON.fromJson(streamReader, clazz);
return new HttpResponse<>(responseCode, response);
} catch (Exception ignored) {
return new HttpResponse<>(-1, null);
} finally {
try {
streamReader.close();
} catch (Exception ignored) {
}
}
}
private static DefaultHttpResponse readDefaultResponse(HttpURLConnection connection) {
InputStreamReader streamReader = createReader(connection);
try {
int responseCode = connection.getResponseCode();
JsonObject response = GSON.fromJson(streamReader, JsonObject.class); JsonObject response = GSON.fromJson(streamReader, JsonObject.class);
return new DefaultHttpResponse(responseCode, response);
return new HttpResponse(responseCode, response);
} catch (Exception exception) { } catch (Exception exception) {
throw new RuntimeException("Failed to read response", exception); throw new RuntimeException("Failed to read response", exception);
} finally { } finally {
@@ -106,10 +117,30 @@ public class HttpUtils {
} }
} }
private static InputStreamReader createReader(HttpURLConnection connection) {
InputStream stream = null;
try {
stream = connection.getInputStream();
} catch (Exception exception) {
try {
stream = connection.getErrorStream();
} catch (Exception exception1) {
throw new RuntimeException("Both the input and the error stream failed?!");
}
}
return new InputStreamReader(stream);
}
@Getter @Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE) @AllArgsConstructor(access = AccessLevel.PRIVATE)
public static final class HttpResponse { public static class HttpResponse<T> {
private final int httpCode; private final int httpCode;
private final JsonObject response; private final T response;
}
public static final class DefaultHttpResponse extends HttpResponse<JsonObject> {
private DefaultHttpResponse(int httpCode, JsonObject response) {
super(httpCode, response);
}
} }
} }

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2019-2021 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Floodgate
*/
package org.geysermc.floodgate.util;
public enum Permissions {
COMMAND_LINK("floodgate.command.linkaccount"),
COMMAND_UNLINK("floodgate.command.unlinkaccount"),
COMMAND_WHITELIST("floodgate.command.fwhitelist"),
NEWS_RECEIVE("floodgate.news.receive");
private final String permission;
Permissions(String permission) {
this.permission = permission;
}
public String get() {
return permission;
}
}

View File

@@ -46,7 +46,7 @@ public final class PrefixCheckTask {
"**********************************\n" + "**********************************\n" +
"* You specified an empty prefix in your Floodgate config for Bedrock players!\n" + "* You specified an empty prefix in your Floodgate config for Bedrock players!\n" +
"* Should a Java player join and a Bedrock player join with the same username, unwanted results and conflicts will happen!\n" + "* Should a Java player join and a Bedrock player join with the same username, unwanted results and conflicts will happen!\n" +
"* We strongly recommend using . as the prefix, but other alternatives that will not conflict include: *, - and +\n" + "* We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *\n" +
"**********************************"); "**********************************");
return; return;
} }
@@ -54,9 +54,9 @@ public final class PrefixCheckTask {
logger.warn( logger.warn(
"\n" + "\n" +
"**********************************\n" + "**********************************\n" +
"The prefix you entered in your Floodgate config ({}) could lead to username conflicts!\n" + "* The prefix you entered in your Floodgate config ({}) could lead to username conflicts!\n" +
"Should a Java player join with the username {}Notch, and a Bedrock player join as Notch (who will be given the name {}Notch), unwanted results will happen!\n" + "* Should a Java player join with the username {}Notch, and a Bedrock player join as Notch (who will be given the name {}Notch), unwanted results will happen!\n" +
"We strongly recommend using . as the prefix, but other alternatives that will not conflict include: *, - and +\n" + "* We strongly recommend using . as the prefix, but other alternatives that will not conflict include: +, - and *\n" +
"**********************************", "**********************************",
config.getUsernamePrefix(), config.getUsernamePrefix(), config.getUsernamePrefix(), config.getUsernamePrefix(),
config.getUsernamePrefix(), config.getUsernamePrefix()); config.getUsernamePrefix(), config.getUsernamePrefix());

View File

@@ -28,6 +28,7 @@ package org.geysermc.floodgate.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@@ -40,8 +41,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.player.UserAudienceArgument.PlayerType; import org.geysermc.floodgate.player.UserAudienceArgument.PlayerType;
import org.geysermc.floodgate.util.SpigotUserAudience.SpigotConsoleAudience; import org.geysermc.floodgate.util.SpigotUserAudience.SpigotConsoleAudience;
@@ -136,12 +137,33 @@ public final class SpigotCommandUtil implements CommandUtil {
} }
@Override @Override
public void sendMessage(Object target, String locale, CommandMessage message, Object... args) { public boolean hasPermission(Object player, String permission) {
((CommandSender) target).sendMessage(translateAndTransform(locale, message, args)); return cast(player).hasPermission(permission);
} }
@Override @Override
public void kickPlayer(Object player, String locale, CommandMessage message, Object... args) { public Collection<Object> getOnlinePlayersWithPermission(String permission) {
List<Object> players = new ArrayList<>();
for (Player player : Bukkit.getOnlinePlayers()) {
if (hasPermission(player, permission)) {
players.add(player);
}
}
return players;
}
@Override
public void sendMessage(Object target, String locale, TranslatableMessage message, Object... args) {
sendMessage(target, translateAndTransform(locale, message, args));
}
@Override
public void sendMessage(Object target, String message) {
((CommandSender) target).sendMessage(message);
}
@Override
public void kickPlayer(Object player, String locale, TranslatableMessage message, Object... args) {
// Have to run this in the main thread so we don't get a `Asynchronous player kick!` error // Have to run this in the main thread so we don't get a `Asynchronous player kick!` error
Bukkit.getScheduler().runTask(plugin, Bukkit.getScheduler().runTask(plugin,
() -> cast(player).kickPlayer(translateAndTransform(locale, message, args))); () -> cast(player).kickPlayer(translateAndTransform(locale, message, args)));
@@ -157,7 +179,7 @@ public final class SpigotCommandUtil implements CommandUtil {
return WhitelistUtils.removePlayer(xuid, username); return WhitelistUtils.removePlayer(xuid, username);
} }
public String translateAndTransform(String locale, CommandMessage message, Object... args) { public String translateAndTransform(String locale, TranslatableMessage message, Object... args) {
// unlike others, Bukkit doesn't have to transform a message into another class. // unlike others, Bukkit doesn't have to transform a message into another class.
return message.translateMessage(manager, locale, args); return message.translateMessage(manager, locale, args);
} }

View File

@@ -37,8 +37,8 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
@RequiredArgsConstructor @RequiredArgsConstructor
@@ -82,7 +82,7 @@ public class SpigotUserAudience implements UserAudience, ForwardingAudience.Sing
} }
@Override @Override
public void sendMessage(CommandMessage message, Object... args) { public void sendMessage(TranslatableMessage message, Object... args) {
commandUtil.sendMessage(source(), locale(), message, args); commandUtil.sendMessage(source(), locale(), message, args);
} }
@@ -94,7 +94,7 @@ public class SpigotUserAudience implements UserAudience, ForwardingAudience.Sing
} }
@Override @Override
public void disconnect(CommandMessage message, Object... args) { public void disconnect(TranslatableMessage message, Object... args) {
commandUtil.kickPlayer(source(), locale(), message, args); commandUtil.kickPlayer(source(), locale(), message, args);
} }

View File

@@ -35,8 +35,8 @@ import net.kyori.adventure.audience.MessageType;
import net.kyori.adventure.identity.Identity; import net.kyori.adventure.identity.Identity;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
@RequiredArgsConstructor @RequiredArgsConstructor
public abstract class VelocityUserAudience implements UserAudience, ForwardingAudience.Single { public abstract class VelocityUserAudience implements UserAudience, ForwardingAudience.Single {
@@ -78,7 +78,7 @@ public abstract class VelocityUserAudience implements UserAudience, ForwardingAu
} }
@Override @Override
public void sendMessage(CommandMessage message, Object... args) { public void sendMessage(TranslatableMessage message, Object... args) {
commandUtil.sendMessage(source(), locale(), message, args); commandUtil.sendMessage(source(), locale(), message, args);
} }
@@ -90,7 +90,7 @@ public abstract class VelocityUserAudience implements UserAudience, ForwardingAu
} }
@Override @Override
public void disconnect(CommandMessage message, Object... args) { public void disconnect(TranslatableMessage message, Object... args) {
commandUtil.kickPlayer(source(), locale(), message, args); commandUtil.kickPlayer(source(), locale(), message, args);
} }

View File

@@ -32,6 +32,7 @@ import com.velocitypowered.api.proxy.ProxyServer;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.UUID; import java.util.UUID;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
@@ -39,8 +40,8 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.floodgate.api.FloodgateApi; import org.geysermc.floodgate.api.FloodgateApi;
import org.geysermc.floodgate.api.logger.FloodgateLogger; import org.geysermc.floodgate.api.logger.FloodgateLogger;
import org.geysermc.floodgate.platform.command.CommandMessage;
import org.geysermc.floodgate.platform.command.CommandUtil; import org.geysermc.floodgate.platform.command.CommandUtil;
import org.geysermc.floodgate.platform.command.TranslatableMessage;
import org.geysermc.floodgate.player.UserAudience; import org.geysermc.floodgate.player.UserAudience;
import org.geysermc.floodgate.player.UserAudienceArgument.PlayerType; import org.geysermc.floodgate.player.UserAudienceArgument.PlayerType;
import org.geysermc.floodgate.player.VelocityUserAudience.VelocityConsoleAudience; import org.geysermc.floodgate.player.VelocityUserAudience.VelocityConsoleAudience;
@@ -134,17 +135,40 @@ public final class VelocityCommandUtil implements CommandUtil {
} }
@Override @Override
public void sendMessage(Object target, String locale, CommandMessage message, Object... args) { public boolean hasPermission(Object player, String permission) {
return cast(player).hasPermission(permission);
}
@Override
public Collection<Object> getOnlinePlayersWithPermission(String permission) {
List<Object> players = new ArrayList<>();
for (Player player : server.getAllPlayers()) {
if (hasPermission(player, permission)) {
players.add(player);
}
}
return players;
}
@Override
public void sendMessage(Object target, String locale, TranslatableMessage message, Object... args) {
((CommandSource) target).sendMessage(translateAndTransform(locale, message, args)); ((CommandSource) target).sendMessage(translateAndTransform(locale, message, args));
} }
@Override @Override
public void kickPlayer(Object player, String locale, CommandMessage message, Object... args) { public void sendMessage(Object target, String message) {
((CommandSource) target).sendMessage(Component.text(message));
}
@Override
public void kickPlayer(Object player, String locale, TranslatableMessage message, Object... args) {
cast(player).disconnect(translateAndTransform(locale, message, args)); cast(player).disconnect(translateAndTransform(locale, message, args));
} }
public Component translateAndTransform(String locale, CommandMessage message, public Component translateAndTransform(
Object... args) { String locale,
TranslatableMessage message,
Object... args) {
return Component.text(message.translateMessage(manager, locale, args)); return Component.text(message.translateMessage(manager, locale, args));
} }