diff --git a/RedisBungee-API/src/main/java/com/imaginarycode/minecraft/redisbungee/internal/AbstractRedisBungeeListener.java b/RedisBungee-API/src/main/java/com/imaginarycode/minecraft/redisbungee/internal/AbstractRedisBungeeListener.java index 3370f4e..c6a736d 100644 --- a/RedisBungee-API/src/main/java/com/imaginarycode/minecraft/redisbungee/internal/AbstractRedisBungeeListener.java +++ b/RedisBungee-API/src/main/java/com/imaginarycode/minecraft/redisbungee/internal/AbstractRedisBungeeListener.java @@ -38,7 +38,7 @@ public abstract class AbstractRedisBungeeListener { public abstract void onPluginMessage(PM event); - private void serializeMultiset(Multiset collection, ByteArrayDataOutput output) { + protected void serializeMultiset(Multiset collection, ByteArrayDataOutput output) { output.writeInt(collection.elementSet().size()); for (Multiset.Entry entry : collection.entrySet()) { output.writeUTF(entry.getElement()); @@ -47,7 +47,7 @@ public abstract class AbstractRedisBungeeListener { } @SuppressWarnings("SameParameterValue") - private void serializeMultimap(Multimap collection, boolean includeNames, ByteArrayDataOutput output) { + protected void serializeMultimap(Multimap collection, boolean includeNames, ByteArrayDataOutput output) { output.writeInt(collection.keySet().size()); for (Map.Entry> entry : collection.asMap().entrySet()) { output.writeUTF(entry.getKey()); diff --git a/RedisBungee-API/src/main/java/com/imaginarycode/minecraft/redisbungee/internal/DataManager.java b/RedisBungee-API/src/main/java/com/imaginarycode/minecraft/redisbungee/internal/DataManager.java index 879d1c1..63334e0 100644 --- a/RedisBungee-API/src/main/java/com/imaginarycode/minecraft/redisbungee/internal/DataManager.java +++ b/RedisBungee-API/src/main/java/com/imaginarycode/minecraft/redisbungee/internal/DataManager.java @@ -24,7 +24,7 @@ import java.util.concurrent.TimeUnit; * * @since 0.3.3 */ -public abstract class DataManager { +public abstract class DataManager { private final RedisBungeePlugin

plugin; private final Cache serverCache = createCache(); private final Cache proxyCache = createCache(); @@ -141,16 +141,15 @@ public abstract class DataManager { } } - private void invalidate(UUID uuid) { + protected void invalidate(UUID uuid) { ipCache.invalidate(uuid); lastOnlineCache.invalidate(uuid); serverCache.invalidate(uuid); proxyCache.invalidate(uuid); } - - + // Invalidate all entries related to this player, since they now lie. (call invalidate(uuid)) public abstract void onPostLogin(PL event); - + // Invalidate all entries related to this player, since they now lie. (call invalidate(uuid)) public abstract void onPlayerDisconnect(PD event); public abstract void onPubSubMessage(PS event); @@ -285,7 +284,7 @@ public abstract class DataManager { private final String server; private final String oldServer; - ServerChangePayload(String server, String oldServer) { + public ServerChangePayload(String server, String oldServer) { this.server = server; this.oldServer = oldServer; } diff --git a/RedisBungee-Bungee/src/main/java/com/imaginarycode/minecraft/redisbungee/BungeeDataManager.java b/RedisBungee-Bungee/src/main/java/com/imaginarycode/minecraft/redisbungee/BungeeDataManager.java new file mode 100644 index 0000000..2532225 --- /dev/null +++ b/RedisBungee-Bungee/src/main/java/com/imaginarycode/minecraft/redisbungee/BungeeDataManager.java @@ -0,0 +1,30 @@ +package com.imaginarycode.minecraft.redisbungee; + +import com.imaginarycode.minecraft.redisbungee.events.bungee.PubSubMessageEvent; +import com.imaginarycode.minecraft.redisbungee.internal.DataManager; +import com.imaginarycode.minecraft.redisbungee.internal.RedisBungeePlugin; +import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.event.PlayerDisconnectEvent; +import net.md_5.bungee.api.event.PostLoginEvent; + +public class BungeeDataManager extends DataManager { + + public BungeeDataManager(RedisBungeePlugin plugin) { + super(plugin); + } + + @Override + public void onPostLogin(PostLoginEvent event) { + invalidate(event.getPlayer().getUniqueId()); + } + + @Override + public void onPlayerDisconnect(PlayerDisconnectEvent event) { + invalidate(event.getPlayer().getUniqueId()); + } + + @Override + public void onPubSubMessage(PubSubMessageEvent event) { + handlePubSubMessage(event.getChannel(), event.getMessage()); + } +} diff --git a/RedisBungee-Bungee/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeListener.java b/RedisBungee-Bungee/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeListener.java index ac17a19..ccbea6f 100644 --- a/RedisBungee-Bungee/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeListener.java +++ b/RedisBungee-Bungee/src/main/java/com/imaginarycode/minecraft/redisbungee/RedisBungeeListener.java @@ -1,12 +1,21 @@ package com.imaginarycode.minecraft.redisbungee; +import com.google.common.base.Joiner; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.Multimap; +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; import com.imaginarycode.minecraft.redisbungee.internal.AbstractRedisBungeeListener; import com.imaginarycode.minecraft.redisbungee.internal.DataManager; import com.imaginarycode.minecraft.redisbungee.internal.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.events.bungee.PubSubMessageEvent; import com.imaginarycode.minecraft.redisbungee.internal.RedisUtil; import com.imaginarycode.minecraft.redisbungee.internal.util.RedisCallable; +import net.md_5.bungee.api.AbstractReconnectHandler; +import net.md_5.bungee.api.config.ServerInfo; import net.md_5.bungee.api.connection.ProxiedPlayer; +import net.md_5.bungee.api.connection.Server; import net.md_5.bungee.api.event.*; import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Plugin; @@ -15,7 +24,7 @@ import redis.clients.jedis.Jedis; import redis.clients.jedis.Pipeline; import java.net.InetAddress; -import java.util.List; +import java.util.*; public class RedisBungeeListener extends AbstractRedisBungeeListener implements Listener { @@ -106,19 +115,135 @@ public class RedisBungeeListener extends AbstractRedisBungeeListener(plugin) { + @Override + protected Void call(Jedis jedis) { + jedis.hset("player:" + event.getPlayer().getUniqueId().toString(), "server", event.getServer().getInfo().getName()); + jedis.publish("redisbungee-data", gson.toJson(new DataManager.DataManagerMessage( + event.getPlayer().getUniqueId(), plugin.getApi().getServerId(), DataManager.DataManagerMessage.Action.SERVER_CHANGE, + new DataManager.ServerChangePayload(event.getServer().getInfo().getName(), currentServer)))); + return null; + } + }); } @Override @EventHandler public void onPing(ProxyPingEvent event) { + if (exemptAddresses.contains(event.getConnection().getAddress().getAddress())) { + return; + } + ServerInfo forced = AbstractReconnectHandler.getForcedHost(event.getConnection()); + if (forced != null && event.getConnection().getListener().isPingPassthrough()) { + return; + } + event.getResponse().getPlayers().setOnline(plugin.getCount()); } @Override + @SuppressWarnings("UnstableApiUsage") @EventHandler public void onPluginMessage(PluginMessageEvent event) { + if ((event.getTag().equals("legacy:redisbungee") || event.getTag().equals("RedisBungee")) && event.getSender() instanceof Server) { + final String currentChannel = event.getTag(); + final byte[] data = Arrays.copyOf(event.getData(), event.getData().length); + plugin.executeAsync(() -> { + ByteArrayDataInput in = ByteStreams.newDataInput(data); + String subchannel = in.readUTF(); + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + String type; + + switch (subchannel) { + case "PlayerList": + out.writeUTF("PlayerList"); + Set original = Collections.emptySet(); + type = in.readUTF(); + if (type.equals("ALL")) { + out.writeUTF("ALL"); + original = plugin.getPlayers(); + } else { + try { + original = plugin.getApi().getPlayersOnServer(type); + } catch (IllegalArgumentException ignored) { + } + } + Set players = new HashSet<>(); + for (UUID uuid : original) + players.add(plugin.getUuidTranslator().getNameFromUuid(uuid, false)); + out.writeUTF(Joiner.on(',').join(players)); + break; + case "PlayerCount": + out.writeUTF("PlayerCount"); + type = in.readUTF(); + if (type.equals("ALL")) { + out.writeUTF("ALL"); + out.writeInt(plugin.getCount()); + } else { + out.writeUTF(type); + try { + out.writeInt(plugin.getApi().getPlayersOnServer(type).size()); + } catch (IllegalArgumentException e) { + out.writeInt(0); + } + } + break; + case "LastOnline": + String user = in.readUTF(); + out.writeUTF("LastOnline"); + out.writeUTF(user); + out.writeLong(plugin.getApi().getLastOnline(plugin.getUuidTranslator().getTranslatedUuid(user, true))); + break; + case "ServerPlayers": + String type1 = in.readUTF(); + out.writeUTF("ServerPlayers"); + Multimap multimap = plugin.getApi().getServerToPlayers(); + + boolean includesUsers; + + switch (type1) { + case "COUNT": + includesUsers = false; + break; + case "PLAYERS": + includesUsers = true; + break; + default: + // TODO: Should I raise an error? + return; + } + + out.writeUTF(type1); + + if (includesUsers) { + Multimap human = HashMultimap.create(); + for (Map.Entry entry : multimap.entries()) { + human.put(entry.getKey(), plugin.getUuidTranslator().getNameFromUuid(entry.getValue(), false)); + } + serializeMultimap(human, true, out); + } else { + serializeMultiset(multimap.keys(), out); + } + break; + case "Proxy": + out.writeUTF("Proxy"); + out.writeUTF(plugin.getConfiguration().getServerId()); + break; + case "PlayerProxy": + String username = in.readUTF(); + out.writeUTF("PlayerProxy"); + out.writeUTF(username); + out.writeUTF(plugin.getApi().getProxy(plugin.getUuidTranslator().getTranslatedUuid(username, true))); + break; + default: + return; + } + + ((Server) event.getSender()).sendData(currentChannel, out.toByteArray()); + }); + } } @Override