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); 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 * This gives you instance of Jedis
* *

View File

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

View File

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

View File

@ -1,48 +1,9 @@
package com.imaginarycode.minecraft.redisbungee.api.util; package com.imaginarycode.minecraft.redisbungee.api.util;
import com.google.common.annotations.VisibleForTesting; 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 @VisibleForTesting
public class RedisUtil { 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) { public static boolean isRedisVersionRight(String redisVersion) {
String[] args = redisVersion.split("\\."); String[] args = redisVersion.split("\\.");
if (args.length < 2) { 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.events.PubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager; import com.imaginarycode.minecraft.redisbungee.api.AbstractDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 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.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.PlayerDisconnectEvent; import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent; import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
import java.util.UUID;
public class BungeeDataManager extends AbstractDataManager<ProxiedPlayer, PostLoginEvent, PlayerDisconnectEvent, PubSubMessageEvent> implements Listener { public class BungeeDataManager extends AbstractDataManager<ProxiedPlayer, PostLoginEvent, PlayerDisconnectEvent, PubSubMessageEvent> implements Listener {
public BungeeDataManager(RedisBungeePlugin<ProxiedPlayer> plugin) { public BungeeDataManager(RedisBungeePlugin<ProxiedPlayer> plugin) {
@ -32,4 +36,13 @@ public class BungeeDataManager extends AbstractDataManager<ProxiedPlayer, PostLo
public void onPubSubMessage(PubSubMessageEvent event) { public void onPubSubMessage(PubSubMessageEvent event) {
handlePubSubMessage(event.getChannel(), event.getMessage()); 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.AbstractDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask; 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.events.PubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.util.RedisUtil;
import net.md_5.bungee.api.AbstractReconnectHandler; import net.md_5.bungee.api.AbstractReconnectHandler;
import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
@ -158,7 +158,7 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
@Override @Override
public Void jedisTask(Jedis jedis) { public Void jedisTask(Jedis jedis) {
Pipeline pipeline = jedis.pipelined(); Pipeline pipeline = jedis.pipelined();
RedisUtil.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), pipeline); PayloadUtils.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), pipeline);
pipeline.sync(); pipeline.sync();
return null; return null;
} }
@ -166,7 +166,7 @@ public class RedisBungeeBungeeListener extends AbstractRedisBungeeListener<Login
@Override @Override
public Void clusterJedisTask(JedisCluster jedisCluster) { public Void clusterJedisTask(JedisCluster jedisCluster) {
// Due some reason JedisCluster does not support pipeline, use instance instead // 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; 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.summoners.JedisSummoner;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask; import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask;
import com.imaginarycode.minecraft.redisbungee.api.util.RedisUtil; 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.commands.RedisBungeeCommands;
import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent; import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent; import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent;
@ -664,7 +665,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
if (!laggedPlayers.isEmpty()) { if (!laggedPlayers.isEmpty()) {
getLogger().info("Cleaning up lagged proxy " + s + " (" + laggedPlayers.size() + " players)..."); getLogger().info("Cleaning up lagged proxy " + s + " (" + laggedPlayers.size() + " players)...");
for (String laggedPlayer : laggedPlayers) { 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) { if (!found) {
RedisUtil.cleanUpPlayer(member, jedis); PayloadUtils.cleanUpPlayer(member, jedis);
getLogger().warning("Player found in set that was not found locally and globally: " + member); getLogger().warning("Player found in set that was not found locally and globally: " + member);
} else { } else {
jedis.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member); jedis.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member);
@ -727,7 +728,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
if (!laggedPlayers.isEmpty()) { if (!laggedPlayers.isEmpty()) {
getLogger().info("Cleaning up lagged proxy " + s + " (" + laggedPlayers.size() + " players)..."); getLogger().info("Cleaning up lagged proxy " + s + " (" + laggedPlayers.size() + " players)...");
for (String laggedPlayer : laggedPlayers) { 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) { if (!found) {
RedisUtil.cleanUpPlayer(member, jedisCluster); PayloadUtils.cleanUpPlayer(member, jedisCluster);
getLogger().warning("Player found in set that was not found locally and globally: " + member); getLogger().warning("Player found in set that was not found locally and globally: " + member);
} else { } else {
jedisCluster.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member); 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) { if (jedis.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) {
Set<String> players = jedis.smembers("proxy:" + configuration.getProxyId() + ":usersOnline"); Set<String> players = jedis.smembers("proxy:" + configuration.getProxyId() + ":usersOnline");
for (String member : players) for (String member : players)
RedisUtil.cleanUpPlayer(member, jedis); PayloadUtils.cleanUpPlayer(member, jedis);
} }
return null; return null;
} }
@ -828,7 +829,7 @@ public class RedisBungeeBungeePlugin extends Plugin implements RedisBungeePlugin
if (jedisCluster.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) { if (jedisCluster.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) {
Set<String> players = jedisCluster.smembers("proxy:" + configuration.getProxyId() + ":usersOnline"); Set<String> players = jedisCluster.smembers("proxy:" + configuration.getProxyId() + ":usersOnline");
for (String member : players) for (String member : players)
RedisUtil.cleanUpPlayer(member, jedisCluster); PayloadUtils.cleanUpPlayer(member, jedisCluster);
} }
return null; 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 @Override
public RedisBungeeMode getRedisBungeeMode() { public RedisBungeeMode getRedisBungeeMode() {
return this.redisBungeeMode; 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.AbstractDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask; 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.events.PubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.util.RedisUtil;
import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.Continuation;
import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.ResultedEvent; import com.velocitypowered.api.event.ResultedEvent;
@ -148,14 +148,14 @@ public class RedisBungeeVelocityListener extends AbstractRedisBungeeListener<Log
@Override @Override
public Void jedisTask(Jedis jedis) { public Void jedisTask(Jedis jedis) {
Pipeline pipeline = jedis.pipelined(); Pipeline pipeline = jedis.pipelined();
RedisUtil.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), pipeline); PayloadUtils.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), pipeline);
pipeline.sync(); pipeline.sync();
return null; return null;
} }
@Override @Override
public Void clusterJedisTask(JedisCluster jedisCluster) { public Void clusterJedisTask(JedisCluster jedisCluster) {
RedisUtil.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), jedisCluster); PayloadUtils.cleanUpPlayer(event.getPlayer().getUniqueId().toString(), jedisCluster);
return null; 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.summoners.Summoner;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask; import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisTask;
import com.imaginarycode.minecraft.redisbungee.api.util.RedisUtil; 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.io.IOUtil;
import com.imaginarycode.minecraft.redisbungee.api.util.lua.LuaManager; import com.imaginarycode.minecraft.redisbungee.api.util.lua.LuaManager;
import com.imaginarycode.minecraft.redisbungee.api.util.uuid.NameFetcher; import com.imaginarycode.minecraft.redisbungee.api.util.uuid.NameFetcher;
@ -693,7 +694,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (!laggedPlayers.isEmpty()) { if (!laggedPlayers.isEmpty()) {
getLogger().info("Cleaning up lagged proxy {} ({} players)...", s, laggedPlayers.size()); getLogger().info("Cleaning up lagged proxy {} ({} players)...", s, laggedPlayers.size());
for (String laggedPlayer : laggedPlayers) { for (String laggedPlayer : laggedPlayers) {
RedisUtil.cleanUpPlayer(laggedPlayer, jedis); PayloadUtils.cleanUpPlayer(laggedPlayer, jedis);
} }
} }
} }
@ -714,7 +715,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
} }
} }
if (!found) { if (!found) {
RedisUtil.cleanUpPlayer(member, jedis); PayloadUtils.cleanUpPlayer(member, jedis);
getLogger().warn("Player found in set that was not found locally and globally: {}", member); getLogger().warn("Player found in set that was not found locally and globally: {}", member);
} else { } else {
jedis.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member); jedis.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member);
@ -756,7 +757,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (!laggedPlayers.isEmpty()) { if (!laggedPlayers.isEmpty()) {
getLogger().info("Cleaning up lagged proxy {} ({} players)...", s, laggedPlayers.size()); getLogger().info("Cleaning up lagged proxy {} ({} players)...", s, laggedPlayers.size());
for (String laggedPlayer : laggedPlayers) { for (String laggedPlayer : laggedPlayers) {
RedisUtil.cleanUpPlayer(laggedPlayer, jedisCluster); PayloadUtils.cleanUpPlayer(laggedPlayer, jedisCluster);
} }
} }
} }
@ -777,7 +778,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
} }
} }
if (!found) { if (!found) {
RedisUtil.cleanUpPlayer(member, jedisCluster); PayloadUtils.cleanUpPlayer(member, jedisCluster);
getLogger().warn("Player found in set that was not found locally and globally: {}", member); getLogger().warn("Player found in set that was not found locally and globally: {}", member);
} else { } else {
jedisCluster.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member); jedisCluster.srem("proxy:" + configuration.getProxyId() + ":usersOnline", member);
@ -811,7 +812,6 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (configuration.doOverrideBungeeCommands()) { if (configuration.doOverrideBungeeCommands()) {
getProxy().getCommandManager().register("glist", new RedisBungeeCommands.GlistCommand(this), "redisbungee", "rglist"); getProxy().getCommandManager().register("glist", new RedisBungeeCommands.GlistCommand(this), "redisbungee", "rglist");
} }
getProxy().getCommandManager().register("sendtoall", new RedisBungeeCommands.SendToAll(this), "rsendtoall"); getProxy().getCommandManager().register("sendtoall", new RedisBungeeCommands.SendToAll(this), "rsendtoall");
getProxy().getCommandManager().register("serverid", new RedisBungeeCommands.ServerId(this), "rserverid"); getProxy().getCommandManager().register("serverid", new RedisBungeeCommands.ServerId(this), "rserverid");
getProxy().getCommandManager().register("serverids", new RedisBungeeCommands.ServerIds(this)); 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("lastseen", new RedisBungeeCommands.LastSeenCommand(this), "rlastseen");
getProxy().getCommandManager().register("ip", new RedisBungeeCommands.IpCommand(this), "playerip", "rip", "rplayerip"); getProxy().getCommandManager().register("ip", new RedisBungeeCommands.IpCommand(this), "playerip", "rip", "rplayerip");
getProxy().getCommandManager().register("find", new RedisBungeeCommands.FindCommand(this), "rfind"); getProxy().getCommandManager().register("find", new RedisBungeeCommands.FindCommand(this), "rfind");
getProxy().getCommandManager().register("networkkick", new RedisBungeeCommands.KickCommand(this));
} }
@Override @Override
@ -841,7 +842,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (jedis.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) { if (jedis.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) {
Set<String> players = jedis.smembers("proxy:" + configuration.getProxyId() + ":usersOnline"); Set<String> players = jedis.smembers("proxy:" + configuration.getProxyId() + ":usersOnline");
for (String member : players) for (String member : players)
RedisUtil.cleanUpPlayer(member, jedis); PayloadUtils.cleanUpPlayer(member, jedis);
} }
return null; return null;
} }
@ -852,7 +853,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player> {
if (jedisCluster.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) { if (jedisCluster.scard("proxy:" + configuration.getProxyId() + ":usersOnline") > 0) {
Set<String> players = jedisCluster.smembers("proxy:" + configuration.getProxyId() + ":usersOnline"); Set<String> players = jedisCluster.smembers("proxy:" + configuration.getProxyId() + ":usersOnline");
for (String member : players) for (String member : players)
RedisUtil.cleanUpPlayer(member, jedisCluster); PayloadUtils.cleanUpPlayer(member, jedisCluster);
} }
return null; 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 @Override
public RedisBungeeMode getRedisBungeeMode() { public RedisBungeeMode getRedisBungeeMode() {
return this.redisBungeeMode; 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.DisconnectEvent;
import com.velocitypowered.api.event.connection.PostLoginEvent; import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.proxy.Player; 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> { 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) { public void onPubSubMessage(PubSubMessageEvent event) {
handlePubSubMessage(event.getChannel(), event.getMessage()); 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.net.InetAddress;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import com.google.common.base.Joiner; import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap; import com.google.common.collect.HashMultimap;