(1.1.1) Fix NullPointerException in plugin on latest BungeeCord
This commit is contained in:
parent
e784d2524d
commit
4bd1aebd04
Binary file not shown.
|
@ -57,8 +57,8 @@ import net.md_5.bungee.BungeeCord;
|
||||||
*/
|
*/
|
||||||
public class EaglerXBungee extends Plugin {
|
public class EaglerXBungee extends Plugin {
|
||||||
|
|
||||||
public static final String NATIVE_BUNGEECORD_BUILD = "1.20-R0.3-SNAPSHOT:67c65e0:1828";
|
public static final String NATIVE_BUNGEECORD_BUILD = "1.20-R0.3-SNAPSHOT:18eae8a:1842";
|
||||||
public static final String NATIVE_WATERFALL_BUILD = "1.20-R0.3-SNAPSHOT:da6aaf6:572";
|
public static final String NATIVE_WATERFALL_BUILD = "1.20-R0.3-SNAPSHOT:37a9ace:577";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CompatWarning.displayCompatWarning();
|
CompatWarning.displayCompatWarning();
|
||||||
|
@ -68,7 +68,7 @@ public class EaglerXBungee extends Plugin {
|
||||||
private EaglerBungeeConfig conf = null;
|
private EaglerBungeeConfig conf = null;
|
||||||
private EventLoopGroup eventLoopGroup;
|
private EventLoopGroup eventLoopGroup;
|
||||||
private Collection<Channel> openChannels;
|
private Collection<Channel> openChannels;
|
||||||
private final Timer closeInactiveConnections;
|
private Timer closeInactiveConnections = null;
|
||||||
private Timer skinServiceTasks = null;
|
private Timer skinServiceTasks = null;
|
||||||
private Timer authServiceTasks = null;
|
private Timer authServiceTasks = null;
|
||||||
private final ChannelFutureListener newChannelListener;
|
private final ChannelFutureListener newChannelListener;
|
||||||
|
@ -80,7 +80,6 @@ public class EaglerXBungee extends Plugin {
|
||||||
public EaglerXBungee() {
|
public EaglerXBungee() {
|
||||||
instance = this;
|
instance = this;
|
||||||
openChannels = new LinkedList();
|
openChannels = new LinkedList();
|
||||||
closeInactiveConnections = new Timer("EaglerXBungee: Network Tick Tasks");
|
|
||||||
newChannelListener = new ChannelFutureListener() {
|
newChannelListener = new ChannelFutureListener() {
|
||||||
@Override
|
@Override
|
||||||
public void operationComplete(ChannelFuture ch) throws Exception {
|
public void operationComplete(ChannelFuture ch) throws Exception {
|
||||||
|
@ -109,7 +108,6 @@ public class EaglerXBungee extends Plugin {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
closeInactiveConnections.scheduleAtFixedRate(EaglerPipeline.closeInactive, 0l, 250l);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -135,11 +133,18 @@ public class EaglerXBungee extends Plugin {
|
||||||
getProxy().registerChannel(EaglerPipeline.UPDATE_CERT_CHANNEL);
|
getProxy().registerChannel(EaglerPipeline.UPDATE_CERT_CHANNEL);
|
||||||
getProxy().registerChannel(VoiceService.CHANNEL);
|
getProxy().registerChannel(VoiceService.CHANNEL);
|
||||||
getProxy().registerChannel(EaglerPacketEventListener.FNAW_SKIN_ENABLE_CHANNEL);
|
getProxy().registerChannel(EaglerPacketEventListener.FNAW_SKIN_ENABLE_CHANNEL);
|
||||||
|
getProxy().registerChannel(EaglerPacketEventListener.GET_DOMAIN_CHANNEL);
|
||||||
startListeners();
|
startListeners();
|
||||||
|
if(closeInactiveConnections != null) {
|
||||||
|
closeInactiveConnections.cancel();
|
||||||
|
closeInactiveConnections = null;
|
||||||
|
}
|
||||||
if(skinServiceTasks != null) {
|
if(skinServiceTasks != null) {
|
||||||
skinServiceTasks.cancel();
|
skinServiceTasks.cancel();
|
||||||
skinServiceTasks = null;
|
skinServiceTasks = null;
|
||||||
}
|
}
|
||||||
|
closeInactiveConnections = new Timer("EaglerXBungee: Network Tick Tasks");
|
||||||
|
closeInactiveConnections.scheduleAtFixedRate(EaglerPipeline.closeInactive, 0l, 250l);
|
||||||
boolean downloadSkins = conf.getDownloadVanillaSkins();
|
boolean downloadSkins = conf.getDownloadVanillaSkins();
|
||||||
if(downloadSkins) {
|
if(downloadSkins) {
|
||||||
if(skinService == null) {
|
if(skinService == null) {
|
||||||
|
@ -211,6 +216,10 @@ public class EaglerXBungee extends Plugin {
|
||||||
getProxy().unregisterChannel(VoiceService.CHANNEL);
|
getProxy().unregisterChannel(VoiceService.CHANNEL);
|
||||||
getProxy().unregisterChannel(EaglerPacketEventListener.FNAW_SKIN_ENABLE_CHANNEL);
|
getProxy().unregisterChannel(EaglerPacketEventListener.FNAW_SKIN_ENABLE_CHANNEL);
|
||||||
stopListeners();
|
stopListeners();
|
||||||
|
if(closeInactiveConnections != null) {
|
||||||
|
closeInactiveConnections.cancel();
|
||||||
|
closeInactiveConnections = null;
|
||||||
|
}
|
||||||
if(skinServiceTasks != null) {
|
if(skinServiceTasks != null) {
|
||||||
skinServiceTasks.cancel();
|
skinServiceTasks.cancel();
|
||||||
skinServiceTasks = null;
|
skinServiceTasks = null;
|
||||||
|
|
|
@ -539,7 +539,7 @@ public class DefaultAuthSystem {
|
||||||
String playerName = player.getName();
|
String playerName = player.getName();
|
||||||
if(!playerName.equals(username)) {
|
if(!playerName.equals(username)) {
|
||||||
EaglerXBungee.logger().info("Player \"" + uuid.toString() + "\" changed their username from \"" + username
|
EaglerXBungee.logger().info("Player \"" + uuid.toString() + "\" changed their username from \"" + username
|
||||||
+ " to \"" + playerName + "\", updating authentication database...");
|
+ "\" to \"" + playerName + "\", updating authentication database...");
|
||||||
synchronized(updateMojangUsername) {
|
synchronized(updateMojangUsername) {
|
||||||
updateMojangUsername.setString(1, playerName);
|
updateMojangUsername.setString(1, playerName);
|
||||||
updateMojangUsername.setString(2, uuidString);
|
updateMojangUsername.setString(2, uuidString);
|
||||||
|
|
|
@ -227,18 +227,9 @@ public class EaglerBungeeConfig {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private static JsonObject parseJsonObject(InputStream file) throws IOException {
|
private static JsonObject parseJsonObject(InputStream file) throws IOException {
|
||||||
StringBuilder str = new StringBuilder();
|
|
||||||
byte[] buffer = new byte[8192];
|
|
||||||
|
|
||||||
int i;
|
|
||||||
while((i = file.read(buffer)) > 0) {
|
|
||||||
str.append(new String(buffer, 0, i, "UTF-8"));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return (new JsonParser()).parse(str.toString()).getAsJsonObject();
|
return JsonParser.parseReader(new InputStreamReader(file, StandardCharsets.UTF_8)).getAsJsonObject();
|
||||||
}catch(JsonSyntaxException ex) {
|
}catch(JsonSyntaxException ex) {
|
||||||
throw new IOException("Invalid JSONObject", ex);
|
throw new IOException("Invalid JSONObject", ex);
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ class VanillaDefaultSkinProfileLoader implements Consumer<Response> {
|
||||||
doNotify();
|
doNotify();
|
||||||
}else {
|
}else {
|
||||||
try {
|
try {
|
||||||
JsonObject json = (new JsonParser()).parse(new String(response.data, StandardCharsets.UTF_8)).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(new String(response.data, StandardCharsets.UTF_8)).getAsJsonObject();
|
||||||
JsonElement propsElement = json.get("properties");
|
JsonElement propsElement = json.get("properties");
|
||||||
if(propsElement != null) {
|
if(propsElement != null) {
|
||||||
JsonArray properties = propsElement.getAsJsonArray();
|
JsonArray properties = propsElement.getAsJsonArray();
|
||||||
|
@ -115,7 +115,7 @@ class VanillaDefaultSkinProfileLoader implements Consumer<Response> {
|
||||||
doNotify();
|
doNotify();
|
||||||
}else {
|
}else {
|
||||||
try {
|
try {
|
||||||
JsonObject json = (new JsonParser()).parse(new String(response.data, StandardCharsets.UTF_8)).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(new String(response.data, StandardCharsets.UTF_8)).getAsJsonObject();
|
||||||
String uuid = json.get("id").getAsString();
|
String uuid = json.get("id").getAsString();
|
||||||
URI requestURI = URI.create("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid + "?unsigned=false");
|
URI requestURI = URI.create("https://sessionserver.mojang.com/session/minecraft/profile/" + uuid + "?unsigned=false");
|
||||||
BinaryHttpClient.asyncRequest("GET", requestURI, new ProfileSkinConsumerImpl(uuid));
|
BinaryHttpClient.asyncRequest("GET", requestURI, new ProfileSkinConsumerImpl(uuid));
|
||||||
|
|
|
@ -56,6 +56,7 @@ import net.md_5.bungee.protocol.Property;
|
||||||
public class EaglerPacketEventListener implements Listener {
|
public class EaglerPacketEventListener implements Listener {
|
||||||
|
|
||||||
public static final String FNAW_SKIN_ENABLE_CHANNEL = "EAG|FNAWSEn-1.8";
|
public static final String FNAW_SKIN_ENABLE_CHANNEL = "EAG|FNAWSEn-1.8";
|
||||||
|
public static final String GET_DOMAIN_CHANNEL = "EAG|GetDomain";
|
||||||
|
|
||||||
public final EaglerXBungee plugin;
|
public final EaglerXBungee plugin;
|
||||||
|
|
||||||
|
@ -104,7 +105,7 @@ public class EaglerPacketEventListener implements Listener {
|
||||||
}
|
}
|
||||||
}else if(event.getSender() instanceof Server && event.getReceiver() instanceof UserConnection) {
|
}else if(event.getSender() instanceof Server && event.getReceiver() instanceof UserConnection) {
|
||||||
UserConnection player = (UserConnection)event.getReceiver();
|
UserConnection player = (UserConnection)event.getReceiver();
|
||||||
if("EAG|GetDomain".equals(event.getTag()) && player.getPendingConnection() instanceof EaglerInitialHandler) {
|
if(GET_DOMAIN_CHANNEL.equals(event.getTag()) && player.getPendingConnection() instanceof EaglerInitialHandler) {
|
||||||
event.setCancelled(true);
|
event.setCancelled(true);
|
||||||
String domain = ((EaglerInitialHandler)player.getPendingConnection()).getOrigin();
|
String domain = ((EaglerInitialHandler)player.getPendingConnection()).getOrigin();
|
||||||
if(domain == null) {
|
if(domain == null) {
|
||||||
|
@ -117,7 +118,6 @@ public class EaglerPacketEventListener implements Listener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@EventHandler
|
@EventHandler
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public void onPostLogin(PostLoginEvent event) {
|
public void onPostLogin(PostLoginEvent event) {
|
||||||
ProxiedPlayer p = event.getPlayer();
|
ProxiedPlayer p = event.getPlayer();
|
||||||
if(p instanceof UserConnection) {
|
if(p instanceof UserConnection) {
|
||||||
|
@ -132,7 +132,7 @@ public class EaglerPacketEventListener implements Listener {
|
||||||
if(pp.getName().equals("textures")) {
|
if(pp.getName().equals("textures")) {
|
||||||
try {
|
try {
|
||||||
String jsonStr = SkinPackets.bytesToAscii(Base64.decodeBase64(pp.getValue()));
|
String jsonStr = SkinPackets.bytesToAscii(Base64.decodeBase64(pp.getValue()));
|
||||||
JsonObject json = (new JsonParser()).parse(jsonStr).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(jsonStr).getAsJsonObject();
|
||||||
JsonObject skinObj = json.getAsJsonObject("SKIN");
|
JsonObject skinObj = json.getAsJsonObject("SKIN");
|
||||||
if(skinObj != null) {
|
if(skinObj != null) {
|
||||||
JsonElement url = json.get("url");
|
JsonElement url = json.get("url");
|
||||||
|
|
|
@ -234,6 +234,21 @@ public class EaglerInitialHandler extends InitialHandler {
|
||||||
return playerUUID;
|
return playerUUID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UUID getRewriteId() {
|
||||||
|
return playerUUID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUniqueId(UUID uuid) {
|
||||||
|
throw new UnsupportedOperationException("EaglercraftXBungee does not support changing player UUIDs at login! (yet)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setOnlineMode(boolean onlineMode) {
|
||||||
|
throw new UnsupportedOperationException("EaglercraftXBungee does not support changing player online mode status at login! (yet)");
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUUID() {
|
public String getUUID() {
|
||||||
return playerUUID.toString().replace("-", "");
|
return playerUUID.toString().replace("-", "");
|
||||||
|
|
|
@ -10,9 +10,13 @@ import java.util.List;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import io.netty.buffer.PooledByteBufAllocator;
|
||||||
import io.netty.channel.Channel;
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelException;
|
||||||
import io.netty.channel.ChannelInitializer;
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelOption;
|
||||||
import io.netty.channel.ChannelPipeline;
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.WriteBufferWaterMark;
|
||||||
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
import io.netty.handler.codec.compression.ZlibCodecFactory;
|
||||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||||
import io.netty.handler.codec.http.HttpServerCodec;
|
import io.netty.handler.codec.http.HttpServerCodec;
|
||||||
|
@ -50,6 +54,9 @@ public class EaglerPipeline {
|
||||||
public static final AttributeKey<InetAddress> REAL_ADDRESS = AttributeKey.valueOf("RealAddress");
|
public static final AttributeKey<InetAddress> REAL_ADDRESS = AttributeKey.valueOf("RealAddress");
|
||||||
public static final AttributeKey<String> HOST = AttributeKey.valueOf("Host");
|
public static final AttributeKey<String> HOST = AttributeKey.valueOf("Host");
|
||||||
public static final AttributeKey<String> ORIGIN = AttributeKey.valueOf("Origin");
|
public static final AttributeKey<String> ORIGIN = AttributeKey.valueOf("Origin");
|
||||||
|
public static final int LOW_MARK = Integer.getInteger("net.md_5.bungee.low_mark", 524288);
|
||||||
|
public static final int HIGH_MARK = Integer.getInteger("net.md_5.bungee.high_mark", 2097152);
|
||||||
|
public static final WriteBufferWaterMark MARK = new WriteBufferWaterMark(LOW_MARK, HIGH_MARK);
|
||||||
|
|
||||||
public static final Collection<Channel> openChannels = new LinkedList();
|
public static final Collection<Channel> openChannels = new LinkedList();
|
||||||
|
|
||||||
|
@ -151,6 +158,11 @@ public class EaglerPipeline {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void initChannel(Channel channel) throws Exception {
|
protected void initChannel(Channel channel) throws Exception {
|
||||||
|
channel.config().setAllocator(PooledByteBufAllocator.DEFAULT).setWriteBufferWaterMark(MARK);
|
||||||
|
try {
|
||||||
|
channel.config().setOption(ChannelOption.IP_TOS, 24);
|
||||||
|
} catch (ChannelException var3) {
|
||||||
|
}
|
||||||
ChannelPipeline pipeline = channel.pipeline();
|
ChannelPipeline pipeline = channel.pipeline();
|
||||||
pipeline.addLast("HttpServerCodec", new HttpServerCodec());
|
pipeline.addLast("HttpServerCodec", new HttpServerCodec());
|
||||||
pipeline.addLast("HttpObjectAggregator", new HttpObjectAggregator(65535));
|
pipeline.addLast("HttpObjectAggregator", new HttpObjectAggregator(65535));
|
||||||
|
|
|
@ -162,7 +162,7 @@ public abstract class HttpServerQueryHandler extends ChannelInboundHandlerAdapte
|
||||||
JsonObject obj = null;
|
JsonObject obj = null;
|
||||||
if(str.indexOf('{') == 0) {
|
if(str.indexOf('{') == 0) {
|
||||||
try {
|
try {
|
||||||
obj = (new JsonParser()).parse(str).getAsJsonObject();
|
obj = JsonParser.parseString(str).getAsJsonObject();
|
||||||
}catch(JsonParseException ex) {
|
}catch(JsonParseException ex) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -917,7 +917,7 @@ public class HttpWebSocketHandler extends ChannelInboundHandlerAdapter {
|
||||||
if("textures".equals(props[i].getName())) {
|
if("textures".equals(props[i].getName())) {
|
||||||
try {
|
try {
|
||||||
String jsonStr = SkinPackets.bytesToAscii(Base64.decodeBase64(props[i].getValue()));
|
String jsonStr = SkinPackets.bytesToAscii(Base64.decodeBase64(props[i].getValue()));
|
||||||
JsonObject json = (new JsonParser()).parse(jsonStr).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(jsonStr).getAsJsonObject();
|
||||||
JsonObject skinObj = json.getAsJsonObject("SKIN");
|
JsonObject skinObj = json.getAsJsonObject("SKIN");
|
||||||
if(skinObj != null) {
|
if(skinObj != null) {
|
||||||
JsonElement url = json.get("url");
|
JsonElement url = json.get("url");
|
||||||
|
@ -990,11 +990,11 @@ public class HttpWebSocketHandler extends ChannelInboundHandlerAdapter {
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PostLoginEvent login = new PostLoginEvent(userCon);
|
bungee.getPluginManager().callEvent(new PostLoginEvent(userCon, server, complete));
|
||||||
|
}catch(NoSuchMethodError err) {
|
||||||
|
PostLoginEvent login = PostLoginEvent.class.getDeclaredConstructor(ProxiedPlayer.class).newInstance(userCon);
|
||||||
bungee.getPluginManager().callEvent(login);
|
bungee.getPluginManager().callEvent(login);
|
||||||
complete.done(login, null);
|
complete.done(login, null);
|
||||||
}catch(NoSuchMethodError err) {
|
|
||||||
bungee.getPluginManager().callEvent(PostLoginEvent.class.getDeclaredConstructor(ProxiedPlayer.class, ServerInfo.class, Callback.class).newInstance(userCon, server, complete));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -212,7 +212,7 @@ public class AsyncSkinProvider {
|
||||||
doAccept(null);
|
doAccept(null);
|
||||||
}else {
|
}else {
|
||||||
try {
|
try {
|
||||||
JsonObject json = (new JsonParser()).parse(new String(response.data, StandardCharsets.UTF_8)).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(new String(response.data, StandardCharsets.UTF_8)).getAsJsonObject();
|
||||||
String username = json.get("name").getAsString().toLowerCase();
|
String username = json.get("name").getAsString().toLowerCase();
|
||||||
String texture = null;
|
String texture = null;
|
||||||
String model = null;
|
String model = null;
|
||||||
|
@ -227,7 +227,7 @@ public class AsyncSkinProvider {
|
||||||
JsonObject propObj = prop.getAsJsonObject();
|
JsonObject propObj = prop.getAsJsonObject();
|
||||||
if(propObj.get("name").getAsString().equals("textures")) {
|
if(propObj.get("name").getAsString().equals("textures")) {
|
||||||
String value = new String(Base64.decodeBase64(propObj.get("value").getAsString()), StandardCharsets.UTF_8);
|
String value = new String(Base64.decodeBase64(propObj.get("value").getAsString()), StandardCharsets.UTF_8);
|
||||||
JsonObject texturesJson = (new JsonParser()).parse(value).getAsJsonObject();
|
JsonObject texturesJson = JsonParser.parseString(value).getAsJsonObject();
|
||||||
if(texturesJson != null && texturesJson.has("textures")) {
|
if(texturesJson != null && texturesJson.has("textures")) {
|
||||||
texturesJson = texturesJson.getAsJsonObject("textures");
|
texturesJson = texturesJson.getAsJsonObject("textures");
|
||||||
JsonElement skin = texturesJson.get("SKIN");
|
JsonElement skin = texturesJson.get("SKIN");
|
||||||
|
|
|
@ -330,7 +330,7 @@ public class SkinService implements ISkinService {
|
||||||
if(pp.getName().equals("textures")) {
|
if(pp.getName().equals("textures")) {
|
||||||
try {
|
try {
|
||||||
String jsonStr = SkinPackets.bytesToAscii(Base64.decodeBase64(pp.getValue()));
|
String jsonStr = SkinPackets.bytesToAscii(Base64.decodeBase64(pp.getValue()));
|
||||||
JsonObject json = (new JsonParser()).parse(jsonStr).getAsJsonObject();
|
JsonObject json = JsonParser.parseString(jsonStr).getAsJsonObject();
|
||||||
JsonObject skinObj = json.getAsJsonObject("SKIN");
|
JsonObject skinObj = json.getAsJsonObject("SKIN");
|
||||||
if(skinObj != null) {
|
if(skinObj != null) {
|
||||||
JsonElement url = json.get("url");
|
JsonElement url = json.get("url");
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name: EaglercraftXBungee
|
name: EaglercraftXBungee
|
||||||
main: net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.EaglerXBungee
|
main: net.lax1dude.eaglercraft.v1_8.plugin.gateway_bungeecord.EaglerXBungee
|
||||||
version: 1.1.0
|
version: 1.1.1
|
||||||
description: Plugin to allow EaglercraftX 1.8 players to join your network, or allow EaglercraftX 1.8 players to use your network as a proxy to join other networks
|
description: Plugin to allow EaglercraftX 1.8 players to join your network, or allow EaglercraftX 1.8 players to use your network as a proxy to join other networks
|
||||||
author: lax1dude
|
author: lax1dude
|
|
@ -1 +1 @@
|
||||||
1.1.0
|
1.1.1
|
Binary file not shown.
|
@ -1 +1 @@
|
||||||
{"pluginName":"EaglercraftXBungee","pluginVersion":"1.1.0","pluginButton":"Download \"EaglerXBungee-1.1.0.jar\"","pluginFilename":"EaglerXBungee.zip"}
|
{"pluginName":"EaglercraftXBungee","pluginVersion":"1.1.1","pluginButton":"Download \"EaglerXBungee-1.1.1.jar\"","pluginFilename":"EaglerXBungee.zip"}
|
Loading…
Reference in New Issue
Block a user