Implement network kick

This commit is contained in:
mohammed jasem alaajel 2022-07-19 15:30:45 +04:00
parent f722b8c9d3
commit c848126aa7
13 changed files with 255 additions and 105 deletions

View File

@ -333,6 +333,30 @@ public class RedisBungeeAPI {
return plugin.getUuidTranslator().getTranslatedUuid(name, expensiveLookups);
}
/**
* Kicks a player from the network
*
* @param playerName player name
* @param message kick message that player will see on kick
* @since 0.8.0
*/
public void kickPlayer(String playerName, String message) {
plugin.kickPlayer(playerName, message);
}
/**
* Kicks a player from the network
*
* @param playerUUID player name
* @param message kick message that player will see on kick
* @since 0.8.0
*/
public void kickPlayer(UUID playerUUID, String message) {
plugin.kickPlayer(playerUUID, message);
}
/**
* This gives you instance of Jedis
*

View File

@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit;
* @since 0.3.3
*/
public abstract class AbstractDataManager<P, PL, PD, PS> {
private final RedisBungeePlugin<P> plugin;
protected final RedisBungeePlugin<P> plugin;
private final Cache<UUID, String> serverCache = createCache();
private final Cache<UUID, String> proxyCache = createCache();
private final Cache<UUID, InetAddress> ipCache = createCache();
@ -44,8 +44,6 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
.build();
}
private final JsonParser parser = new JsonParser();
public String getServer(final UUID uuid) {
P player = plugin.getPlayer(uuid);
@ -174,14 +172,16 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
public abstract void onPubSubMessage(PS event);
public abstract boolean handleKick(UUID target, String message);
protected void handlePubSubMessage(String channel, String message) {
if (!channel.equals("redisbungee-data"))
return;
// Partially deserialize the message so we can look at the action
JsonObject jsonObject = parser.parse(message).getAsJsonObject();
JsonObject jsonObject = JsonParser.parseString(message).getAsJsonObject();
String source = jsonObject.get("source").getAsString();
final String source = jsonObject.get("source").getAsString();
if (source.equals(plugin.getConfiguration().getProxyId()))
return;
@ -190,24 +190,20 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
switch (action) {
case JOIN:
final DataManagerMessage<LoginPayload> message1 = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<LoginPayload>>() {
}.getType());
final DataManagerMessage<LoginPayload> message1 = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<LoginPayload>>() {}.getType());
proxyCache.put(message1.getTarget(), message1.getSource());
lastOnlineCache.put(message1.getTarget(), (long) 0);
ipCache.put(message1.getTarget(), message1.getPayload().getAddress());
plugin.executeAsync(new Runnable() {
@Override
public void run() {
Object event;
try {
event = plugin.getNetworkJoinEventClass().getDeclaredConstructor(UUID.class).newInstance(message1.getTarget());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an network join event", e);
}
plugin.callEvent(event);
plugin.executeAsync(() -> {
Object event;
try {
event = plugin.getNetworkJoinEventClass().getDeclaredConstructor(UUID.class).newInstance(message1.getTarget());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an network join event", e);
}
plugin.callEvent(event);
});
break;
case LEAVE:
@ -215,42 +211,40 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
}.getType());
invalidate(message2.getTarget());
lastOnlineCache.put(message2.getTarget(), message2.getPayload().getTimestamp());
plugin.executeAsync(new Runnable() {
@Override
public void run() {
Object event;
try {
event = plugin.getNetworkQuitEventClass().getDeclaredConstructor(UUID.class).newInstance(message2.getTarget());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an network quit event", e);
}
plugin.callEvent(event);
plugin.executeAsync(() -> {
Object event;
try {
event = plugin.getNetworkQuitEventClass().getDeclaredConstructor(UUID.class).newInstance(message2.getTarget());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an network quit event", e);
}
plugin.callEvent(event);
});
break;
case SERVER_CHANGE:
final DataManagerMessage<ServerChangePayload> message3 = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<ServerChangePayload>>() {
}.getType());
final DataManagerMessage<ServerChangePayload> message3 = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<ServerChangePayload>>() {}.getType());
serverCache.put(message3.getTarget(), message3.getPayload().getServer());
plugin.executeAsync(new Runnable() {
@Override
public void run() {
Object event;
try {
event = plugin.getServerChangeEventClass().getDeclaredConstructor(UUID.class, String.class, String.class).newInstance(message3.getTarget(), ((ServerChangePayload) message3.getPayload()).getOldServer(), ((ServerChangePayload) message3.getPayload()).getServer());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an server change event", e);
}
plugin.callEvent(event);
plugin.executeAsync(() -> {
Object event;
try {
event = plugin.getServerChangeEventClass().getDeclaredConstructor(UUID.class, String.class, String.class).newInstance(message3.getTarget(), ((ServerChangePayload) message3.getPayload()).getOldServer(), ((ServerChangePayload) message3.getPayload()).getServer());
} catch (InstantiationException | IllegalAccessException | InvocationTargetException |
NoSuchMethodException e) {
throw new RuntimeException("unable to dispatch an server change event", e);
}
plugin.callEvent(event);
});
break;
case KICK:
final DataManagerMessage<KickPayload> kickPayload = gson.fromJson(jsonObject, new TypeToken<DataManagerMessage<KickPayload>>() {}.getType());
plugin.executeAsync(() -> handleKick(kickPayload.target, kickPayload.payload.message));
break;
}
}
public static class DataManagerMessage<T> {
public static class DataManagerMessage<T extends Payload> {
private final UUID target;
private final String source;
private final Action action; // for future use!
@ -282,11 +276,27 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
public enum Action {
JOIN,
LEAVE,
KICK,
SERVER_CHANGE
}
}
public static class LoginPayload {
public static abstract class Payload {}
public static class KickPayload extends Payload {
private final String message;
public KickPayload(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
}
public static class LoginPayload extends Payload{
private final InetAddress address;
public LoginPayload(InetAddress address) {
@ -298,7 +308,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
}
}
public static class ServerChangePayload {
public static class ServerChangePayload extends Payload{
private final String server;
private final String oldServer;
@ -317,7 +327,7 @@ public abstract class AbstractDataManager<P, PL, PD, PS> {
}
public static class LogoutPayload {
public static class LogoutPayload extends Payload{
private final long timestamp;
public LogoutPayload(long timestamp) {

View File

@ -67,4 +67,6 @@ public abstract class AbstractRedisBungeeListener<LE, PLE, PD, SC, PP, PM, PS> {
}
public abstract void onPubSubMessage(PS event);
}

View File

@ -94,6 +94,10 @@ public interface RedisBungeePlugin<P> extends EventsPlatform {
void loadConfig() throws Exception;
void kickPlayer(UUID playerUniqueId, String message);
void kickPlayer(String playerName, String message);
RedisBungeeMode getRedisBungeeMode();
Long getRedisClusterTime();

View File

@ -1,48 +1,9 @@
package com.imaginarycode.minecraft.redisbungee.api.util;
import com.google.common.annotations.VisibleForTesting;
import com.google.gson.Gson;
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.Pipeline;
import java.util.UUID;
@VisibleForTesting
public class RedisUtil {
private static final Gson gson = new Gson();
public static void cleanUpPlayer(String player, Jedis rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", player);
rsc.hdel("player:" + player, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + player, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(player), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void cleanUpPlayer(String player, Pipeline rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", player);
rsc.hdel("player:" + player, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + player, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(player), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void cleanUpPlayer(String player, JedisCluster rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", player);
rsc.hdel("player:" + player, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + player, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(player), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static boolean isRedisVersionRight(String redisVersion) {
String[] args = redisVersion.split("\\.");
if (args.length < 2) {

View File

@ -0,0 +1,65 @@
package com.imaginarycode.minecraft.redisbungee.api.util.payload;
import com.google.gson.Gson;
import com.imaginarycode.minecraft.redisbungee.RedisBungeeAPI;
import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.Pipeline;
import java.util.UUID;
public class PayloadUtils {
private static final Gson gson = new Gson();
public static void cleanUpPlayer(String uuid, Jedis rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", uuid);
rsc.hdel("player:" + uuid, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + uuid, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(uuid), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void cleanUpPlayer(String uuid, Pipeline rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", uuid);
rsc.hdel("player:" + uuid, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + uuid, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(uuid), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void cleanUpPlayer(String uuid, JedisCluster rsc) {
rsc.srem("proxy:" + RedisBungeeAPI.getRedisBungeeApi().getProxyId() + ":usersOnline", uuid);
rsc.hdel("player:" + uuid, "server", "ip", "proxy");
long timestamp = System.currentTimeMillis();
rsc.hset("player:" + uuid, "online", String.valueOf(timestamp));
rsc.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
UUID.fromString(uuid), RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.LEAVE,
new AbstractDataManager.LogoutPayload(timestamp))));
}
public static void kickPlayer(UUID uuid, String message, Pipeline pipeline) {
System.out.println(uuid);
pipeline.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
uuid, RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.KICK,
new AbstractDataManager.KickPayload(message))));
}
public static void kickPlayer(UUID uuid, String message, Jedis jedis) {
System.out.println(uuid);
jedis.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
uuid, RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.KICK,
new AbstractDataManager.KickPayload(message))));
}
public static void kickPlayer(UUID uuid, String message, JedisCluster jedisCluster) {
System.out.println(uuid);
jedisCluster.publish("redisbungee-data", gson.toJson(new AbstractDataManager.DataManagerMessage<>(
uuid, RedisBungeeAPI.getRedisBungeeApi().getProxyId(), AbstractDataManager.DataManagerMessage.Action.KICK,
new AbstractDataManager.KickPayload(message))));
}
}

View File

@ -3,12 +3,16 @@ package com.imaginarycode.minecraft.redisbungee;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.util.UUID;
public class BungeeDataManager extends AbstractDataManager<ProxiedPlayer, PostLoginEvent, PlayerDisconnectEvent, PubSubMessageEvent> implements Listener {
public BungeeDataManager(RedisBungeePlugin<ProxiedPlayer> plugin) {
@ -32,4 +36,13 @@ public class BungeeDataManager extends AbstractDataManager<ProxiedPlayer, PostLo
public void onPubSubMessage(PubSubMessageEvent event) {
handlePubSubMessage(event.getChannel(), event.getMessage());
}
@Override
public boolean handleKick(UUID target, String message) {
// check if the player is online on this proxy
ProxiedPlayer player = plugin.getPlayer(target);
if (player == null) return false;
player.disconnect(TextComponent.fromLegacyText(message));
return true;
}
}

View File

@ -10,8 +10,8 @@ import com.imaginarycode.minecraft.redisbungee.api.AbstractRedisBungeeListener;
import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask;
import com.imaginarycode.minecraft.redisbungee.api.util.payload.PayloadUtils;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.util.RedisUtil;
import net.md_5.bungee.api.AbstractReconnectHandler;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer;
@ -158,7 +158,7 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
@Override
public Void jedisTask(Jedis jedis) {
Pipeline pipeline = jedis.pipelined();
RedisUtil.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), pipeline);
PayloadUtils.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), pipeline);
pipeline.sync();
return null;
}
@ -166,7 +166,7 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
@Override
public Void clusterJedisTask(JedisCluster jedisCluster) {
// Due some reason JedisCluster does not support pipeline, use instance instead
RedisUtil.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), jedisCluster);
PayloadUtils.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), jedisCluster);
return null;
}
});

View File

@ -11,6 +11,7 @@ import com.imaginarycode.minecraft.redisbungee.api.summoners.ClusterJedisSummone
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisSummoner;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask;
import com.imaginarycode.minecraft.redisbungee.api.util.RedisUtil;
import com.imaginarycode.minecraft.redisbungee.api.util.payload.PayloadUtils;
import com.imaginarycode.minecraft.redisbungee.commands.RedisBungeeCommands;
import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent;
@ -664,7 +665,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
if (!laggedPlayers.isEmpty()) {
getLogger().info("Cleaning up lagged proxy " + s + " (" + laggedPlayers.size() + " players)...");
for (String laggedPlayer : laggedPlayers) {
RedisUtil.cleanUpPlayer(laggedPlayer, jedis);
PayloadUtils.cleanUpPlayer(laggedPlayer, jedis);
}
}
}
@ -685,7 +686,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
}
}
if (!found) {
RedisUtil.cleanUpPlayer(member, jedis);
PayloadUtils.cleanUpPlayer(member, jedis);
getLogger().warning("Player found in set that was not found locally and globally: " + member);
} else {
jedis.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member);
@ -727,7 +728,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
if (!laggedPlayers.isEmpty()) {
getLogger().info("Cleaning up lagged proxy " + s + " (" + laggedPlayers.size() + " players)...");
for (String laggedPlayer : laggedPlayers) {
RedisUtil.cleanUpPlayer(laggedPlayer, jedisCluster);
PayloadUtils.cleanUpPlayer(laggedPlayer, jedisCluster);
}
}
}
@ -748,7 +749,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
}
}
if (!found) {
RedisUtil.cleanUpPlayer(member, jedisCluster);
PayloadUtils.cleanUpPlayer(member, jedisCluster);
getLogger().warning("Player found in set that was not found locally and globally: " + member);
} else {
jedisCluster.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member);
@ -817,7 +818,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
if (jedis.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) {
Set<String> players = jedis.smembers("proxy:" + configuration.getProxyId() + ":usersOnline");
for (String member : players)
RedisUtil.cleanUpPlayer(member, jedis);
PayloadUtils.cleanUpPlayer(member, jedis);
}
return null;
}
@ -828,7 +829,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
if (jedisCluster.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) {
Set<String> players = jedisCluster.smembers("proxy:" + configuration.getProxyId() + ":usersOnline");
for (String member : players)
RedisUtil.cleanUpPlayer(member, jedisCluster);
PayloadUtils.cleanUpPlayer(member, jedisCluster);
}
return null;
}
@ -915,6 +916,30 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
}
}
@Override
public void kickPlayer(UUID playerUniqueId, String message) {
new RedisTask<Void>(api) {
@Override
public Void jedisTask(Jedis jedis) {
PayloadUtils.kickPlayer(playerUniqueId, message, jedis);
return null;
}
@Override
public Void clusterJedisTask(JedisCluster jedisCluster) {
PayloadUtils.kickPlayer(playerUniqueId, message, jedisCluster);
return null;
}
}.execute();
}
@Override
public void kickPlayer(String playerName, String message) {
// fetch the uuid
UUID playerUUID = this.uuidTranslator.getTranslatedUuid(playerName,true);
kickPlayer(playerUUID, message);
}
@Override
public RedisBungeeMode getRedisBungeeMode() {
return this.redisBungeeMode;

View File

@ -10,8 +10,8 @@ import com.imaginarycode.minecraft.redisbungee.api.AbstractRedisBungeeListener;
import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask;
import com.imaginarycode.minecraft.redisbungee.api.util.payload.PayloadUtils;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.util.RedisUtil;
import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.ResultedEvent;
@ -148,14 +148,14 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
@Override
public Void jedisTask(Jedis jedis) {
Pipeline pipeline = jedis.pipelined();
RedisUtil.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), pipeline);
PayloadUtils.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), pipeline);
pipeline.sync();
return null;
}
@Override
public Void clusterJedisTask(JedisCluster jedisCluster) {
RedisUtil.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), jedisCluster);
PayloadUtils.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), jedisCluster);
return null;
}

View File

@ -14,6 +14,7 @@ import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisSummoner;
import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask;
import com.imaginarycode.minecraft.redisbungee.api.util.RedisUtil;
import com.imaginarycode.minecraft.redisbungee.api.util.payload.PayloadUtils;
import com.imaginarycode.minecraft.redisbungee.api.util.io.IOUtil;
import com.imaginarycode.minecraft.redisbungee.api.util.lua.LuaManager;
import com.imaginarycode.minecraft.redisbungee.api.util.uuid.NameFetcher;
@ -693,7 +694,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (!laggedPlayers.isEmpty()) {
getLogger().info("Cleaning up lagged proxy {} ({} players)...", s, laggedPlayers.size());
for (String laggedPlayer : laggedPlayers) {
RedisUtil.cleanUpPlayer(laggedPlayer, jedis);
PayloadUtils.cleanUpPlayer(laggedPlayer, jedis);
}
}
}
@ -714,7 +715,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
}
}
if (!found) {
RedisUtil.cleanUpPlayer(member, jedis);
PayloadUtils.cleanUpPlayer(member, jedis);
getLogger().warn("Player found in set that was not found locally and globally: {}", member);
} else {
jedis.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member);
@ -756,7 +757,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (!laggedPlayers.isEmpty()) {
getLogger().info("Cleaning up lagged proxy {} ({} players)...", s, laggedPlayers.size());
for (String laggedPlayer : laggedPlayers) {
RedisUtil.cleanUpPlayer(laggedPlayer, jedisCluster);
PayloadUtils.cleanUpPlayer(laggedPlayer, jedisCluster);
}
}
}
@ -777,7 +778,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
}
}
if (!found) {
RedisUtil.cleanUpPlayer(member, jedisCluster);
PayloadUtils.cleanUpPlayer(member, jedisCluster);
getLogger().warn("Player found in set that was not found locally and globally: {}", member);
} else {
jedisCluster.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member);
@ -811,7 +812,6 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (configuration.doOverrideBungeeCommands()) {
getProxy().getCommandManager().register("glist", new RedisBungeeCommands.GlistCommand(this), "redisbungee", "rglist");
}
getProxy().getCommandManager().register("sendtoall", new RedisBungeeCommands.SendToAll(this), "rsendtoall");
getProxy().getCommandManager().register("serverid", new RedisBungeeCommands.ServerId(this), "rserverid");
getProxy().getCommandManager().register("serverids", new RedisBungeeCommands.ServerIds(this));
@ -820,6 +820,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
getProxy().getCommandManager().register("lastseen", new RedisBungeeCommands.LastSeenCommand(this), "rlastseen");
getProxy().getCommandManager().register("ip", new RedisBungeeCommands.IpCommand(this), "playerip", "rip", "rplayerip");
getProxy().getCommandManager().register("find", new RedisBungeeCommands.FindCommand(this), "rfind");
getProxy().getCommandManager().register("networkkick", new RedisBungeeCommands.KickCommand(this));
}
@Override
@ -841,7 +842,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (jedis.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) {
Set<String> players = jedis.smembers("proxy:" + configuration.getProxyId() + ":usersOnline");
for (String member : players)
RedisUtil.cleanUpPlayer(member, jedis);
PayloadUtils.cleanUpPlayer(member, jedis);
}
return null;
}
@ -852,7 +853,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (jedisCluster.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) {
Set<String> players = jedisCluster.smembers("proxy:" + configuration.getProxyId() + ":usersOnline");
for (String member : players)
RedisUtil.cleanUpPlayer(member, jedisCluster);
PayloadUtils.cleanUpPlayer(member, jedisCluster);
}
return null;
}
@ -954,6 +955,33 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
}
}
@Override
public void kickPlayer(UUID playerUniqueId, String message) {
// first handle on origin proxy if player not found publish the payload
if (!dataManager.handleKick(playerUniqueId, message)) {
new RedisTask<Void>(api) {
@Override
public Void jedisTask(Jedis jedis) {
PayloadUtils.kickPlayer(playerUniqueId, message, jedis);
return null;
}
@Override
public Void clusterJedisTask(JedisCluster jedisCluster) {
PayloadUtils.kickPlayer(playerUniqueId, message, jedisCluster);
return null;
}
}.execute();
}
}
@Override
public void kickPlayer(String playerName, String message) {
// fetch the uuid
UUID playerUUID = this.uuidTranslator.getTranslatedUuid(playerName,true);
kickPlayer(playerUUID, message);
}
@Override
public RedisBungeeMode getRedisBungeeMode() {
return this.redisBungeeMode;

View File

@ -7,6 +7,11 @@ import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.DisconnectEvent;
import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.proxy.Player;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.TextComponent;
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
import java.util.UUID;
public class VelocityDataManager extends AbstractDataManager<Player, PostLoginEvent, DisconnectEvent, PubSubMessageEvent> {
@ -32,4 +37,15 @@ public class VelocityDataManager extends AbstractDataManager<Player, PostLoginEv
public void onPubSubMessage(PubSubMessageEvent event) {
handlePubSubMessage(event.getChannel(), event.getMessage());
}
private final LegacyComponentSerializer serializer = LegacyComponentSerializer.legacySection();
@Override
public boolean handleKick(UUID target, String message) {
Player player = plugin.getPlayer(target);
if (player == null) {
return false;
}
player.disconnect(serializer.deserialize(message));
return true;
}
}

View File

@ -2,9 +2,11 @@ package com.imaginarycode.minecraft.redisbungee.commands;
import java.net.InetAddress;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap;