· 6 years ago · Jan 31, 2020, 01:04 PM
1package nescaaallz.dc;
2
3import com.google.common.io.ByteArrayDataOutput;
4import com.google.common.io.ByteStreams;
5import java.net.InetSocketAddress;
6import java.util.ArrayDeque;
7import java.util.HashMap;
8import java.util.List;
9import java.util.Map;
10import java.util.Queue;
11import java.util.WeakHashMap;
12import java.util.concurrent.CompletableFuture;
13import java.util.function.BiFunction;
14import org.bukkit.Bukkit;
15import org.bukkit.entity.Player;
16import org.bukkit.plugin.Plugin;
17import org.bukkit.plugin.messaging.Messenger;
18import org.bukkit.plugin.messaging.PluginMessageListener;
19
20public class BungeeChannelApi {
21 private static WeakHashMap<Plugin, BungeeChannelApi> registeredInstances = new WeakHashMap<>();
22
23 private final PluginMessageListener messageListener;
24
25 private final Plugin plugin;
26
27 private final Map<String, Queue<CompletableFuture<?>>> callbackMap;
28
29 private Map<String, ForwardConsumer> forwardListeners;
30
31 private ForwardConsumer globalForwardListener;
32
33 public static synchronized BungeeChannelApi of(Plugin plugin) {
34 return registeredInstances.compute(plugin, (k, v) -> {
35 if (v == null)
36 v = new BungeeChannelApi(paramPlugin1);
37 return v;
38 });
39 }
40
41 public BungeeChannelApi(Plugin plugin) {
42 this.plugin = plugin;
43 this.callbackMap = new HashMap<>();
44 synchronized (registeredInstances) {
45 registeredInstances.compute(plugin, (k, oldInstance) -> {
46 if (oldInstance != null)
47 oldInstance.unregister();
48 return this;
49 });
50 }
51 this.messageListener = this::onPluginMessageReceived;
52 Messenger messenger = Bukkit.getServer().getMessenger();
53 messenger.registerOutgoingPluginChannel(plugin, "BungeeCord");
54 messenger.registerIncomingPluginChannel(plugin, "BungeeCord", this.messageListener);
55 }
56
57 public void registerForwardListener(ForwardConsumer globalListener) {
58 this.globalForwardListener = globalListener;
59 }
60
61 public void registerForwardListener(String targetChannel, ForwardConsumer listener) {
62 if (this.forwardListeners == null)
63 this.forwardListeners = new HashMap<>();
64 synchronized (this.forwardListeners) {
65 this.forwardListeners.put(targetChannel, listener);
66 }
67 }
68
69 public CompletableFuture<Integer> getPlayerCount(String serverName) {
70 Player player = getFirstPlayer();
71 CompletableFuture<Integer> future = new CompletableFuture<>();
72 synchronized (this.callbackMap) {
73 this.callbackMap.compute("PlayerCount", computeQueueValue(future));
74 }
75 ByteArrayDataOutput output = ByteStreams.newDataOutput();
76 output.writeUTF("PlayerCount");
77 output.writeUTF(serverName);
78 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
79 return future;
80 }
81
82 public CompletableFuture<List<String>> getPlayerList(String serverName) {
83 Player player = getFirstPlayer();
84 CompletableFuture<List<String>> future = new CompletableFuture<>();
85 synchronized (this.callbackMap) {
86 this.callbackMap.compute("PlayerList", computeQueueValue(future));
87 }
88 ByteArrayDataOutput output = ByteStreams.newDataOutput();
89 output.writeUTF("PlayerList");
90 output.writeUTF(serverName);
91 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
92 return future;
93 }
94
95 public CompletableFuture<List<String>> getServers() {
96 Player player = getFirstPlayer();
97 CompletableFuture<List<String>> future = new CompletableFuture<>();
98 synchronized (this.callbackMap) {
99 this.callbackMap.compute("GetServers", computeQueueValue(future));
100 }
101 ByteArrayDataOutput output = ByteStreams.newDataOutput();
102 output.writeUTF("GetServers");
103 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
104 return future;
105 }
106
107 public void connect(Player player, String serverName) {
108 ByteArrayDataOutput output = ByteStreams.newDataOutput();
109 output.writeUTF("Connect");
110 output.writeUTF(serverName);
111 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
112 }
113
114 public void connectOther(String playerName, String server) {
115 Player player = getFirstPlayer();
116 ByteArrayDataOutput output = ByteStreams.newDataOutput();
117 output.writeUTF("ConnectOther");
118 output.writeUTF(playerName);
119 output.writeUTF(server);
120 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
121 }
122
123 public CompletableFuture<InetSocketAddress> getIp(Player player) {
124 CompletableFuture<InetSocketAddress> future = new CompletableFuture<>();
125 synchronized (this.callbackMap) {
126 this.callbackMap.compute("IP", computeQueueValue(future));
127 }
128 ByteArrayDataOutput output = ByteStreams.newDataOutput();
129 output.writeUTF("IP");
130 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
131 return future;
132 }
133
134 public void sendMessage(String playerName, String message) {
135 Player player = getFirstPlayer();
136 ByteArrayDataOutput output = ByteStreams.newDataOutput();
137 output.writeUTF("Message");
138 output.writeUTF(playerName);
139 output.writeUTF(message);
140 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
141 }
142
143 public CompletableFuture<String> getServer() {
144 Player player = getFirstPlayer();
145 CompletableFuture<String> future = new CompletableFuture<>();
146 synchronized (this.callbackMap) {
147 this.callbackMap.compute("GetServer", computeQueueValue(future));
148 }
149 ByteArrayDataOutput output = ByteStreams.newDataOutput();
150 output.writeUTF("GetServer");
151 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
152 return future;
153 }
154
155 public CompletableFuture<String> getUUID(Player player) {
156 CompletableFuture<String> future = new CompletableFuture<>();
157 synchronized (this.callbackMap) {
158 this.callbackMap.compute("UUID", computeQueueValue(future));
159 }
160 ByteArrayDataOutput output = ByteStreams.newDataOutput();
161 output.writeUTF("UUID");
162 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
163 return future;
164 }
165
166 public CompletableFuture<String> getUUID(String playerName) {
167 Player player = getFirstPlayer();
168 CompletableFuture<String> future = new CompletableFuture<>();
169 synchronized (this.callbackMap) {
170 this.callbackMap.compute("UUIDOther", computeQueueValue(future));
171 }
172 ByteArrayDataOutput output = ByteStreams.newDataOutput();
173 output.writeUTF("UUIDOther");
174 output.writeUTF(playerName);
175 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
176 return future;
177 }
178
179 public CompletableFuture<InetSocketAddress> getServerIp(String serverName) {
180 Player player = getFirstPlayer();
181 CompletableFuture<InetSocketAddress> future = new CompletableFuture<>();
182 synchronized (this.callbackMap) {
183 this.callbackMap.compute("ServerIP", computeQueueValue(future));
184 }
185 ByteArrayDataOutput output = ByteStreams.newDataOutput();
186 output.writeUTF("ServerIP");
187 output.writeUTF(serverName);
188 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
189 return future;
190 }
191
192 public void kickPlayer(String playerName, String kickMessage) {
193 Player player = getFirstPlayer();
194 CompletableFuture<InetSocketAddress> future = new CompletableFuture<>();
195 synchronized (this.callbackMap) {
196 this.callbackMap.compute("KickPlayer", computeQueueValue(future));
197 }
198 ByteArrayDataOutput output = ByteStreams.newDataOutput();
199 output.writeUTF("KickPlayer");
200 output.writeUTF(playerName);
201 output.writeUTF(kickMessage);
202 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
203 }
204
205 public void forward(String server, String channelName, byte[] data) {
206 Player player = getFirstPlayer();
207 ByteArrayDataOutput output = ByteStreams.newDataOutput();
208 output.writeUTF("Forward");
209 output.writeUTF(server);
210 output.writeUTF(channelName);
211 output.writeShort(data.length);
212 output.write(data);
213 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
214 }
215
216 public void forwardToPlayer(String playerName, String channelName, byte[] data) {
217 Player player = getFirstPlayer();
218 ByteArrayDataOutput output = ByteStreams.newDataOutput();
219 output.writeUTF("ForwardToPlayer");
220 output.writeUTF(playerName);
221 output.writeUTF(channelName);
222 output.writeShort(data.length);
223 output.write(data);
224 player.sendPluginMessage(this.plugin, "BungeeCord", output.toByteArray());
225 }
226
227 private void onPluginMessageReceived(String paramString, Player paramPlayer, byte[] paramArrayOfbyte) {
228 throw new Error("Unresolved compilation problems: \n\tThe method complete(capture#3-of ?) in the type CompletableFuture<capture#3-of ?> is not applicable for the arguments (Object)\n\tThe method complete(capture#4-of ?) in the type CompletableFuture<capture#4-of ?> is not applicable for the arguments (List<String>)\n\tType mismatch: cannot convert from List<String> to capture#4-of ?\n\tThe method complete(capture#5-of ?) in the type CompletableFuture<capture#5-of ?> is not applicable for the arguments (InetSocketAddress)\n\tThe method complete(capture#6-of ?) in the type CompletableFuture<capture#6-of ?> is not applicable for the arguments (List<String>)\n\tType mismatch: cannot convert from List<String> to capture#6-of ?\n\tThe method complete(capture#7-of ?) in the type CompletableFuture<capture#7-of ?> is not applicable for the arguments (String)\n\tThe method complete(capture#8-of ?) in the type CompletableFuture<capture#8-of ?> is not applicable for the arguments (InetSocketAddress)\n\tThe method complete(capture#9-of ?) in the type CompletableFuture<capture#9-of ?> is not applicable for the arguments (String)\n");
229 }
230
231 public void unregister() {
232 Messenger messenger = Bukkit.getServer().getMessenger();
233 messenger.unregisterIncomingPluginChannel(this.plugin, "BungeeCord", this.messageListener);
234 messenger.unregisterOutgoingPluginChannel(this.plugin);
235 this.callbackMap.clear();
236 }
237
238 private BiFunction<String, Queue<CompletableFuture<?>>, Queue<CompletableFuture<?>>> computeQueueValue(CompletableFuture<?> queueValue) {
239 return (key, value) -> {
240 if (value == null)
241 value = new ArrayDeque<>();
242 value.add(paramCompletableFuture);
243 return value;
244 };
245 }
246
247 private Player getFirstPlayer() {
248 Player ret = Bukkit.getOnlinePlayers()[0];
249 if (ret == null)
250 throw new IllegalArgumentException("Bungee Messaging Api requires at least one player online.");
251 return ret;
252 }
253
254 @FunctionalInterface
255 public static interface ForwardConsumer {
256 void accept(String param1String, Player param1Player, byte[] param1ArrayOfbyte);
257 }
258}