CachedPlayerHeads/src/main/java/org/warp/cachedplayerheads/BungeeAPI.java
Andrea Cavalli 9d1f489996 First commit
2021-04-19 20:53:45 +02:00

108 lines
3.6 KiB
Java

package org.warp.cachedplayerheads;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.bukkit.Bukkit;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.messaging.PluginMessageListener;
import org.jetbrains.annotations.Nullable;
public class BungeeAPI implements PluginMessageListener {
private final Plugin playerheads;
private final ConcurrentHashMap<UUID, CompletableFuture<String>> requests = new ConcurrentHashMap<>();
private static final ScheduledExecutorService executor;
static {
executor = Executors.newSingleThreadScheduledExecutor();
}
public BungeeAPI(Plugin playerheads) {
this.playerheads = playerheads;
playerheads.getServer().getMessenger()
.registerIncomingPluginChannel(playerheads, "cachedplayerheads:channel", this);
playerheads.getServer().getMessenger()
.registerOutgoingPluginChannel(playerheads, "cachedplayerheads:channel");
}
private boolean checkIfBungee() {
@Nullable ConfigurationSection settings = playerheads
.getServer()
.spigot()
.getConfig()
.getConfigurationSection("settings");
if (settings == null || !settings.getBoolean("settings.bungeecord")) {
playerheads.getLogger().severe("This server is not BungeeCord.");
return false;
} else {
playerheads.getLogger().severe("This server is BungeeCord.");
return true;
}
}
public CompletableFuture<String> getPlayerTexture(String playerName) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("PlayerTextureRequest");
UUID reqUUID = UUID.randomUUID();
out.writeLong(reqUUID.getMostSignificantBits());
out.writeLong(reqUUID.getLeastSignificantBits());
out.writeUTF(playerName);
CompletableFuture<String> futureResult = new CompletableFuture<>();
requests.put(reqUUID, futureResult);
try {
System.out.println("Asking player texture. Request: " + reqUUID);
Bukkit.getServer().sendPluginMessage(playerheads, "cachedplayerheads:channel", out.toByteArray());
} catch (Exception ex) {
requests.remove(reqUUID);
throw ex;
}
CompletableFuture<String> timeoutFuture = new CompletableFuture<>();
executor.schedule(() -> {
requests.remove(reqUUID);
timeoutFuture.completeExceptionally(new TimeoutException());
}, 30, TimeUnit.SECONDS);
return CompletableFuture.anyOf(futureResult, timeoutFuture).thenApply(x -> (String) x);
}
@Override
public void onPluginMessageReceived(String channel, Player player, byte[] message) {
if (!channel.equalsIgnoreCase("cachedplayerheads:channel")) {
return;
}
ByteArrayDataInput in = ByteStreams.newDataInput(message);
String subchannel = in.readUTF();
if (subchannel.equals("PlayerTextureResponse")) {
long msb = in.readLong();
long lsb = in.readLong();
boolean hasString = in.readBoolean();
String skinData = hasString ? in.readUTF() : null;
UUID reqUUID = new UUID(msb, lsb);
System.out.println("Received player texture. Request: " + reqUUID);
CompletableFuture<String> req = requests.get(reqUUID);
if (req != null) {
req.complete(skinData);
} else {
System.out.println("Received response for unknown request: " + reqUUID);
}
} else {
System.err.println("Invalid subchannel: " + subchannel);
}
}
}