Merge pull request #6 from feature/animated-motd to master
* commit 'b65ca5f7dd8e07d2d65e59d08a7d907d29b172d6': Update bungee cord, comment out debug stuff Fix icon animation + some more tweaks Some adjustments Motd stuff for xmas update pushing this for my laptop. not final code!
This commit is contained in:
commit
14c6c1ca4b
@ -0,0 +1,8 @@
|
||||
<component name="ArtifactManager">
|
||||
<artifact name="Mineplex.Bungee.Mineplexer:test">
|
||||
<output-path>$PROJECT_DIR$/../Testing/Bungee/plugins</output-path>
|
||||
<root id="root">
|
||||
<element id="artifact" artifact-name="Mineplex.Bungee.Mineplexer:jar" />
|
||||
</root>
|
||||
</artifact>
|
||||
</component>
|
@ -2,20 +2,19 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/Classpath.Dummy/Classpath.Dummy.iml" filepath="$PROJECT_DIR$/Classpath.Dummy/Classpath.Dummy.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Bungee.Mineplexer/Mineplex.Bungee.Mineplexer.iml" filepath="$PROJECT_DIR$/Mineplex.Bungee.Mineplexer/Mineplex.Bungee.Mineplexer.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Core/Mineplex.Core.iml" filepath="$PROJECT_DIR$/Mineplex.Core/Mineplex.Core.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Core.Common/Mineplex.Core.Common.iml" filepath="$PROJECT_DIR$/Mineplex.Core.Common/Mineplex.Core.Common.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Database/Mineplex.Database.iml" filepath="$PROJECT_DIR$/Mineplex.Database/Mineplex.Database.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Classpath.Dummy/Classpath.Dummy.iml" filepath="$PROJECT_DIR$/Classpath.Dummy/Classpath.Dummy.iml" group="Core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Bungee.Mineplexer/Mineplex.Bungee.Mineplexer.iml" filepath="$PROJECT_DIR$/Mineplex.Bungee.Mineplexer/Mineplex.Bungee.Mineplexer.iml" group="Bungee" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Core/Mineplex.Core.iml" filepath="$PROJECT_DIR$/Mineplex.Core/Mineplex.Core.iml" group="Core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Core.Common/Mineplex.Core.Common.iml" filepath="$PROJECT_DIR$/Mineplex.Core.Common/Mineplex.Core.Common.iml" group="Core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Database/Mineplex.Database.iml" filepath="$PROJECT_DIR$/Mineplex.Database/Mineplex.Database.iml" group="Core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Hub/Mineplex.Hub.iml" filepath="$PROJECT_DIR$/Mineplex.Hub/Mineplex.Hub.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.MapParser/Mineplex.MapParser.iml" filepath="$PROJECT_DIR$/Mineplex.MapParser/Mineplex.MapParser.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Minecraft.BungeeSigns/Mineplex.Minecraft.BungeeSigns.iml" filepath="$PROJECT_DIR$/Mineplex.Minecraft.BungeeSigns/Mineplex.Minecraft.BungeeSigns.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Minecraft.Game.ClassCombat/Mineplex.Minecraft.Game.ClassCombat.iml" filepath="$PROJECT_DIR$/Mineplex.Minecraft.Game.ClassCombat/Mineplex.Minecraft.Game.ClassCombat.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Minecraft.Game.Core/Mineplex.Minecraft.Game.Core.iml" filepath="$PROJECT_DIR$/Mineplex.Minecraft.Game.Core/Mineplex.Minecraft.Game.Core.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.ServerData/Mineplex.ServerData.iml" filepath="$PROJECT_DIR$/Mineplex.ServerData/Mineplex.ServerData.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.ServerMonitor/Mineplex.ServerMonitor.iml" filepath="$PROJECT_DIR$/Mineplex.ServerMonitor/Mineplex.ServerMonitor.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Nautilus.Game.Arcade/Nautilus.Game.Arcade.iml" filepath="$PROJECT_DIR$/Nautilus.Game.Arcade/Nautilus.Game.Arcade.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Minecraft.BungeeSigns/Mineplex.Minecraft.BungeeSigns.iml" filepath="$PROJECT_DIR$/Mineplex.Minecraft.BungeeSigns/Mineplex.Minecraft.BungeeSigns.iml" group="Bungee" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Minecraft.Game.ClassCombat/Mineplex.Minecraft.Game.ClassCombat.iml" filepath="$PROJECT_DIR$/Mineplex.Minecraft.Game.ClassCombat/Mineplex.Minecraft.Game.ClassCombat.iml" group="Arcade" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.Minecraft.Game.Core/Mineplex.Minecraft.Game.Core.iml" filepath="$PROJECT_DIR$/Mineplex.Minecraft.Game.Core/Mineplex.Minecraft.Game.Core.iml" group="Arcade" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.ServerData/Mineplex.ServerData.iml" filepath="$PROJECT_DIR$/Mineplex.ServerData/Mineplex.ServerData.iml" group="Core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Mineplex.ServerMonitor/Mineplex.ServerMonitor.iml" filepath="$PROJECT_DIR$/Mineplex.ServerMonitor/Mineplex.ServerMonitor.iml" group="Core" />
|
||||
<module fileurl="file://$PROJECT_DIR$/Nautilus.Game.Arcade/Nautilus.Game.Arcade.iml" filepath="$PROJECT_DIR$/Nautilus.Game.Arcade/Nautilus.Game.Arcade.iml" group="Arcade" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
|
||||
</project>
|
31
Plugins/.idea/runConfigurations/Bungee.xml
Normal file
31
Plugins/.idea/runConfigurations/Bungee.xml
Normal file
@ -0,0 +1,31 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Bungee" type="Application" factoryName="Application" singleton="true">
|
||||
<extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
|
||||
<option name="MAIN_CLASS_NAME" value="net.md_5.bungee.Bootstrap" />
|
||||
<option name="VM_PARAMETERS" value="" />
|
||||
<option name="PROGRAM_PARAMETERS" value="" />
|
||||
<option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../Testing/Bungee" />
|
||||
<option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
|
||||
<option name="ALTERNATIVE_JRE_PATH" value="" />
|
||||
<option name="ENABLE_SWING_INSPECTOR" value="false" />
|
||||
<option name="ENV_VARIABLES" />
|
||||
<option name="PASS_PARENT_ENVS" value="true" />
|
||||
<module name="Mineplex.Bungee.Mineplexer" />
|
||||
<envs />
|
||||
<RunnerSettings RunnerId="Cover" />
|
||||
<RunnerSettings RunnerId="Debug">
|
||||
<option name="DEBUG_PORT" value="" />
|
||||
<option name="TRANSPORT" value="0" />
|
||||
<option name="LOCAL" value="true" />
|
||||
</RunnerSettings>
|
||||
<RunnerSettings RunnerId="Run" />
|
||||
<ConfigurationWrapper RunnerId="Cover" />
|
||||
<ConfigurationWrapper RunnerId="Debug" />
|
||||
<ConfigurationWrapper RunnerId="Run" />
|
||||
<method>
|
||||
<option name="BuildArtifacts" enabled="true">
|
||||
<artifact name="Mineplex.Bungee.Mineplexer:test" />
|
||||
</option>
|
||||
</method>
|
||||
</configuration>
|
||||
</component>
|
Binary file not shown.
@ -0,0 +1,179 @@
|
||||
package mineplex.bungee.motd;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.Favicon;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.connection.CustomMotd;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.protocol.packet.StatusResponse;
|
||||
import org.apache.commons.io.comparator.NameFileComparator;
|
||||
|
||||
public class Motd implements CustomMotd
|
||||
{
|
||||
private static final int MAX_TICKS = 30;
|
||||
private static final char SNOWFLAKE = '❅';
|
||||
private static final String SNOWMAN = ChatColor.WHITE + "☃" + ChatColor.RESET;
|
||||
private static final String LEFT_SWORD = "§b§l§m §8§l§m[ §r";
|
||||
private static final String RIGHT_SWORD = "§8§l§m ]§b§l§m §r";
|
||||
private static final ChatColor[] COLOR_ROTATION =
|
||||
{ChatColor.RED, ChatColor.LIGHT_PURPLE, ChatColor.GOLD, ChatColor.BLUE, ChatColor.YELLOW, ChatColor.GREEN, ChatColor.AQUA};
|
||||
private static List<Favicon> ICON_FRAMES;
|
||||
|
||||
private MotdManager _manager;
|
||||
private ScheduledFuture _task;
|
||||
private int _ticks = 0;
|
||||
|
||||
public Motd(MotdManager manager)
|
||||
{
|
||||
_manager = manager;
|
||||
}
|
||||
|
||||
public void handlePing(final ProxyPingEvent pingResult, final InitialHandler initialHandler)
|
||||
{
|
||||
BungeeCord.getInstance().getConnectionThrottle().unthrottle(initialHandler.getAddress().getAddress());
|
||||
final Gson gson = initialHandler.getHandshake().getProtocolVersion() == 4?BungeeCord.getInstance().gsonLegacy:BungeeCord.getInstance().gson;
|
||||
|
||||
_task = initialHandler.getChannelWrapper().getHandle().eventLoop().scheduleAtFixedRate(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
if (initialHandler.getChannelWrapper().getHandle().isOpen() && _ticks <= MAX_TICKS)
|
||||
{
|
||||
ServerPing ping = pingResult.getResponse();
|
||||
|
||||
String desc = getDesc();
|
||||
ping.setDescription(desc);
|
||||
|
||||
Favicon icon = getIcon();
|
||||
if (icon != null)
|
||||
ping.setFavicon(icon);
|
||||
|
||||
initialHandler.unsafe().sendPacket(new StatusResponse(gson.toJson(ping)));
|
||||
_ticks++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_task.cancel(true);
|
||||
if (initialHandler.getChannelWrapper().getHandle().isOpen())
|
||||
initialHandler.getChannelWrapper().getHandle().close();
|
||||
}
|
||||
}
|
||||
}, 0, 200, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private String getDesc()
|
||||
{
|
||||
int insetSpaces = 8;
|
||||
int maxSpaces = 6;
|
||||
|
||||
ChatColor mineplexColor = COLOR_ROTATION[_ticks % COLOR_ROTATION.length];
|
||||
int spaceLeftCount;
|
||||
int spaceNumber = _ticks % (maxSpaces*2);
|
||||
if (spaceNumber > maxSpaces)
|
||||
spaceLeftCount = 2*maxSpaces - spaceNumber;
|
||||
else
|
||||
spaceLeftCount = spaceNumber;
|
||||
|
||||
String spacesLeft = getRepeatedCharacters(' ', spaceLeftCount);
|
||||
String spacesRight = getRepeatedCharacters(' ', maxSpaces - spaceLeftCount);
|
||||
String insets = getRepeatedCharacters(' ', insetSpaces);
|
||||
String desc = insets + spacesLeft + LEFT_SWORD + spacesRight + getMineplex(mineplexColor) + spacesRight + RIGHT_SWORD + spacesLeft;
|
||||
|
||||
List<String> lines = _manager.getMotdLines();
|
||||
if (lines != null && lines.size() > 0)
|
||||
{
|
||||
int index = _ticks / (MAX_TICKS / (lines.size()-1));
|
||||
String currentLine = index >= lines.size() ? lines.get(lines.size() - 1) : lines.get(index);
|
||||
desc += "\n" + currentLine;
|
||||
}
|
||||
|
||||
return desc;
|
||||
}
|
||||
|
||||
private Favicon getIcon()
|
||||
{
|
||||
Favicon icon = null;
|
||||
|
||||
if (ICON_FRAMES.size() > 0)
|
||||
{
|
||||
icon = ICON_FRAMES.get(_ticks % ICON_FRAMES.size());
|
||||
}
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
private String getMineplex(ChatColor color)
|
||||
{
|
||||
return " " + color + ChatColor.BOLD.toString() + "Mineplex" + ChatColor.RESET + ChatColor.WHITE + ChatColor.BOLD + " Games" + ChatColor.RESET + " ";
|
||||
}
|
||||
|
||||
private String getRepeatedCharacters(char c, int count)
|
||||
{
|
||||
char[] spaces = new char[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
spaces[i] = c;
|
||||
}
|
||||
return new String(spaces);
|
||||
}
|
||||
|
||||
private static Comparator<File> FILE_NUMBER_COMPARATOR = new Comparator<File>()
|
||||
{
|
||||
@Override
|
||||
public int compare(File f1, File f2)
|
||||
{
|
||||
int compareValue = 0;
|
||||
|
||||
try
|
||||
{
|
||||
int i1 = Integer.parseInt(f1.getName().substring(0, f1.getName().indexOf('.')));
|
||||
int i2 = Integer.parseInt(f2.getName().substring(0, f2.getName().indexOf('.')));
|
||||
return i1 - i2;
|
||||
}
|
||||
catch (Exception e) {}
|
||||
|
||||
return compareValue;
|
||||
}
|
||||
};
|
||||
|
||||
static
|
||||
{
|
||||
// Load icon animations
|
||||
ICON_FRAMES = new ArrayList<Favicon>();
|
||||
|
||||
File iconFolder = new File("server-icon");
|
||||
if (iconFolder.exists() && iconFolder.isDirectory())
|
||||
{
|
||||
File[] files = iconFolder.listFiles();
|
||||
Arrays.sort(files, FILE_NUMBER_COMPARATOR);
|
||||
for (int i = 0; i < files.length; i++)
|
||||
{
|
||||
File file = files[i];
|
||||
try
|
||||
{
|
||||
BufferedImage image = ImageIO.read(file);
|
||||
Favicon favicon = Favicon.create(image);
|
||||
ICON_FRAMES.add(favicon);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// Just ignore extra files
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,42 +1,52 @@
|
||||
package mineplex.bungee.motd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import net.md_5.bungee.api.event.PreLoginEvent;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.api.plugin.Listener;
|
||||
import net.md_5.bungee.api.plugin.Plugin;
|
||||
import net.md_5.bungee.connection.CustomMotd;
|
||||
import net.md_5.bungee.connection.CustomMotdFactory;
|
||||
import net.md_5.bungee.connection.InitialHandler;
|
||||
import net.md_5.bungee.event.EventHandler;
|
||||
|
||||
public class MotdManager implements Listener, Runnable
|
||||
public class MotdManager implements Listener, Runnable, CustomMotdFactory
|
||||
{
|
||||
private Plugin _plugin;
|
||||
private MotdRepository _repository;
|
||||
|
||||
private String _motd = "§b§l§m §8§l§m[ §r §9§lMineplex§r §f§lGames§r §8§l§m ]§b§l§m §r §c§l§m§kZ§6§l§m§kZ§e§l§m§kZ§a§l§m§kZ§b§l§m§kZ§r §f§lPLAY NOW§r §b§l§m§kZ§a§l§m§kZ§e§l§m§kZ§6§l§m§kZ§c§l§m§kZ";
|
||||
|
||||
private List<String> _motdLines;
|
||||
|
||||
public MotdManager(Plugin plugin)
|
||||
{
|
||||
_plugin = plugin;
|
||||
|
||||
_plugin.getProxy().getScheduler().schedule(_plugin, this, 30L, 30L, TimeUnit.SECONDS);
|
||||
_plugin.getProxy().getScheduler().schedule(_plugin, this, 5L, 30L, TimeUnit.SECONDS);
|
||||
_plugin.getProxy().getPluginManager().registerListener(_plugin, this);
|
||||
|
||||
_repository = new MotdRepository();
|
||||
_repository.initialize();
|
||||
|
||||
InitialHandler.setCustomMotdFactory(this); // For animated motd
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void ServerPing(ProxyPingEvent event)
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
net.md_5.bungee.api.ServerPing serverPing = event.getResponse();
|
||||
|
||||
event.setResponse(new net.md_5.bungee.api.ServerPing(serverPing.getVersion(), serverPing.getPlayers(), _motd, serverPing.getFaviconObject()));
|
||||
_motdLines = _repository.retrieveMotd();
|
||||
}
|
||||
|
||||
public List<String> getMotdLines()
|
||||
{
|
||||
return _motdLines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
public CustomMotd makeMotd()
|
||||
{
|
||||
_motd = _repository.retrieveMotd();
|
||||
return new Motd(this);
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,10 @@ import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
|
||||
public class MotdRepository
|
||||
{
|
||||
@ -51,9 +55,15 @@ public class MotdRepository
|
||||
System.out.println("Initialized MOTD.");
|
||||
}
|
||||
|
||||
public String retrieveMotd()
|
||||
public List<String> retrieveMotd()
|
||||
{
|
||||
String motd = "§b§l§m §8§l§m[ §r §9§lMineplex§r §f§lGames§r §8§l§m ]§b§l§m §r §c§l§m§kZ§6§l§m§kZ§e§l§m§kZ§a§l§m§kZ§b§l§m§kZ§r §f§lPLAY NOW§r §b§l§m§kZ§a§l§m§kZ§e§l§m§kZ§6§l§m§kZ§c§l§m§kZ";
|
||||
// String motd = "§b§l§m §8§l§m[ §r §9§lMineplex§r §f§lGames§r §8§l§m ]§b§l§m §r §c§l§m§kZ§6§l§m§kZ§e§l§m§kZ§a§l§m§kZ§b§l§m§kZ§r §f§lPLAY NOW§r §b§l§m§kZ§a§l§m§kZ§e§l§m§kZ§6§l§m§kZ§c§l§m§kZ";
|
||||
ArrayList<String> lines = new ArrayList<String>();
|
||||
// lines.add(" " + ChatColor.WHITE + ChatColor.BOLD + "New Game" + ChatColor.RED + ChatColor.BOLD + " Christmas Chaos");
|
||||
// lines.add(" " + ChatColor.WHITE + ChatColor.BOLD + "Winter Sale" + ChatColor.BLUE + ChatColor.BOLD + " 33% Off Everything");
|
||||
// lines.add(" " + ChatColor.WHITE + ChatColor.BOLD + "New Game" + ChatColor.RED + ChatColor.BOLD + " Christmas Chaos");
|
||||
// return lines;
|
||||
|
||||
ResultSet resultSet = null;
|
||||
PreparedStatement preparedStatement = null;
|
||||
|
||||
@ -67,7 +77,7 @@ public class MotdRepository
|
||||
|
||||
while (resultSet.next())
|
||||
{
|
||||
return resultSet.getString(1);
|
||||
lines.add(resultSet.getString(1));
|
||||
}
|
||||
}
|
||||
catch (Exception exception)
|
||||
@ -101,6 +111,6 @@ public class MotdRepository
|
||||
}
|
||||
}
|
||||
|
||||
return motd;
|
||||
return lines;
|
||||
}
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public class PlayerCount implements Listener, Runnable
|
||||
public void ServerPing(ProxyPingEvent event)
|
||||
{
|
||||
net.md_5.bungee.api.ServerPing serverPing = event.getResponse();
|
||||
|
||||
event.setResponse(new net.md_5.bungee.api.ServerPing(serverPing.getVersion(), new Players(_totalPlayers + 1, _totalPlayers, null), serverPing.getDescription(), serverPing.getFaviconObject()));
|
||||
|
||||
event.setResponse(new net.md_5.bungee.api.ServerPing(serverPing.getVersion(), new Players(0, _totalPlayers, null), serverPing.getDescription(), serverPing.getFaviconObject()));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
package net.md_5.bungee.connection;
|
||||
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
|
||||
public interface CustomMotd
|
||||
{
|
||||
public void handlePing(ProxyPingEvent event, InitialHandler initialHandler);
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package net.md_5.bungee.connection;
|
||||
|
||||
public interface CustomMotdFactory
|
||||
{
|
||||
public CustomMotd makeMotd();
|
||||
}
|
@ -0,0 +1,469 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by Fernflower decompiler)
|
||||
//
|
||||
|
||||
package net.md_5.bungee.connection;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.gson.Gson;
|
||||
import java.beans.ConstructorProperties;
|
||||
import java.math.BigInteger;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.channels.Channel;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import javax.crypto.SecretKey;
|
||||
import net.md_5.bungee.BungeeCipher;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.BungeeServerInfo;
|
||||
import net.md_5.bungee.EncryptionUtil;
|
||||
import net.md_5.bungee.UserConnection;
|
||||
import net.md_5.bungee.Util;
|
||||
import net.md_5.bungee.api.AbstractReconnectHandler;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.ChatColor;
|
||||
import net.md_5.bungee.api.Favicon;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.ServerPing.PlayerInfo;
|
||||
import net.md_5.bungee.api.ServerPing.Players;
|
||||
import net.md_5.bungee.api.ServerPing.Protocol;
|
||||
import net.md_5.bungee.api.chat.BaseComponent;
|
||||
import net.md_5.bungee.api.chat.TextComponent;
|
||||
import net.md_5.bungee.api.config.ListenerInfo;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.api.connection.PendingConnection;
|
||||
import net.md_5.bungee.api.connection.ProxiedPlayer;
|
||||
import net.md_5.bungee.api.connection.Connection.Unsafe;
|
||||
import net.md_5.bungee.api.event.LoginEvent;
|
||||
import net.md_5.bungee.api.event.PlayerHandshakeEvent;
|
||||
import net.md_5.bungee.api.event.PostLoginEvent;
|
||||
import net.md_5.bungee.api.event.PreLoginEvent;
|
||||
import net.md_5.bungee.api.event.ProxyPingEvent;
|
||||
import net.md_5.bungee.chat.ComponentSerializer;
|
||||
import net.md_5.bungee.connection.LoginResult;
|
||||
import net.md_5.bungee.connection.UpstreamBridge;
|
||||
import net.md_5.bungee.http.HttpClient;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.netty.HandlerBoss;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.netty.cipher.CipherDecoder;
|
||||
import net.md_5.bungee.netty.cipher.CipherEncoder;
|
||||
import net.md_5.bungee.protocol.DefinedPacket;
|
||||
import net.md_5.bungee.protocol.packet.EncryptionRequest;
|
||||
import net.md_5.bungee.protocol.packet.EncryptionResponse;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import net.md_5.bungee.protocol.packet.Kick;
|
||||
import net.md_5.bungee.protocol.packet.LegacyHandshake;
|
||||
import net.md_5.bungee.protocol.packet.LegacyPing;
|
||||
import net.md_5.bungee.protocol.packet.LoginRequest;
|
||||
import net.md_5.bungee.protocol.packet.LoginSuccess;
|
||||
import net.md_5.bungee.protocol.packet.PingPacket;
|
||||
import net.md_5.bungee.protocol.packet.PluginMessage;
|
||||
import net.md_5.bungee.protocol.packet.StatusRequest;
|
||||
import net.md_5.bungee.protocol.packet.StatusResponse;
|
||||
|
||||
public class InitialHandler extends PacketHandler implements PendingConnection {
|
||||
|
||||
private static CustomMotdFactory _customMotdFactory;
|
||||
|
||||
private final ProxyServer bungee;
|
||||
private ChannelWrapper ch;
|
||||
private final ListenerInfo listener;
|
||||
private Handshake handshake;
|
||||
private LoginRequest loginRequest;
|
||||
private EncryptionRequest request;
|
||||
private final List<PluginMessage> registerMessages = new ArrayList();
|
||||
private InitialHandler.State thisState;
|
||||
private final Unsafe unsafe;
|
||||
private boolean onlineMode;
|
||||
private InetSocketAddress virtualHost;
|
||||
private UUID uniqueId;
|
||||
private UUID offlineId;
|
||||
private LoginResult loginProfile;
|
||||
private boolean legacy;
|
||||
|
||||
public void connected(ChannelWrapper channel) throws Exception {
|
||||
this.ch = channel;
|
||||
}
|
||||
|
||||
public void exception(Throwable t) throws Exception {
|
||||
this.disconnect((String)(ChatColor.RED + Util.exception(t)));
|
||||
}
|
||||
|
||||
public void handle(PluginMessage pluginMessage) throws Exception {
|
||||
if(pluginMessage.getTag().equals("REGISTER")) {
|
||||
Preconditions.checkState(this.registerMessages.size() < 128, "Too many channels registered");
|
||||
this.registerMessages.add(pluginMessage);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void handle(LegacyHandshake legacyHandshake) throws Exception {
|
||||
this.legacy = true;
|
||||
this.ch.getHandle().writeAndFlush(this.bungee.getTranslation("outdated_client", new Object[0]));
|
||||
this.ch.close();
|
||||
}
|
||||
|
||||
public void handle(LegacyPing ping) throws Exception {
|
||||
this.legacy = true;
|
||||
final boolean v1_5 = ping.isV1_5();
|
||||
ServerPing legacy = new ServerPing(new Protocol(this.bungee.getName() + " " + this.bungee.getGameVersion(), this.bungee.getProtocolVersion()), new Players(this.listener.getMaxPlayers(), this.bungee.getOnlineCount(), (PlayerInfo[])null), this.listener.getMotd(), (Favicon)null);
|
||||
Callback callback = new Callback<ProxyPingEvent>() {
|
||||
public void done(ProxyPingEvent result, Throwable error) {
|
||||
if(!InitialHandler.this.ch.isClosed()) {
|
||||
ServerPing legacy = result.getResponse();
|
||||
String kickMessage;
|
||||
if(v1_5) {
|
||||
kickMessage = ChatColor.DARK_BLUE + "\u0000" + 127 + '\u0000' + legacy.getVersion().getName() + '\u0000' + InitialHandler.getFirstLine(legacy.getDescription()) + '\u0000' + legacy.getPlayers().getOnline() + '\u0000' + legacy.getPlayers().getMax();
|
||||
} else {
|
||||
kickMessage = ChatColor.stripColor(InitialHandler.getFirstLine(legacy.getDescription())) + '§' + legacy.getPlayers().getOnline() + '§' + legacy.getPlayers().getMax();
|
||||
}
|
||||
|
||||
InitialHandler.this.ch.getHandle().writeAndFlush(kickMessage);
|
||||
InitialHandler.this.ch.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.bungee.getPluginManager().callEvent(new ProxyPingEvent(this, legacy, callback));
|
||||
}
|
||||
|
||||
private static String getFirstLine(String str) {
|
||||
int pos = str.indexOf(10);
|
||||
return pos == -1?str:str.substring(0, pos);
|
||||
}
|
||||
|
||||
public void handle(StatusRequest statusRequest) throws Exception {
|
||||
Preconditions.checkState(this.thisState == InitialHandler.State.STATUS, "Not expecting STATUS");
|
||||
ServerInfo forced = AbstractReconnectHandler.getForcedHost(this);
|
||||
String motd = forced != null?forced.getMotd():this.listener.getMotd();
|
||||
Callback pingBack = new Callback<ServerPing>() {
|
||||
public void done(ServerPing result, Throwable error) {
|
||||
if(error != null) {
|
||||
result = new ServerPing();
|
||||
result.setDescription(InitialHandler.this.bungee.getTranslation("ping_cannot_connect", new Object[0]));
|
||||
InitialHandler.this.bungee.getLogger().log(Level.WARNING, "Error pinging remote server", error);
|
||||
}
|
||||
|
||||
Callback callback = new Callback<ProxyPingEvent>() {
|
||||
public void done(ProxyPingEvent pingResult, Throwable error) {
|
||||
// MINEPLEX
|
||||
if (_customMotdFactory != null)
|
||||
{
|
||||
_customMotdFactory.makeMotd().handlePing(pingResult, InitialHandler.this);
|
||||
}
|
||||
else
|
||||
{
|
||||
BungeeCord.getInstance().getConnectionThrottle().unthrottle(InitialHandler.this.getAddress().getAddress());
|
||||
Gson gson = InitialHandler.this.handshake.getProtocolVersion() == 4?BungeeCord.getInstance().gsonLegacy:BungeeCord.getInstance().gson;
|
||||
InitialHandler.this.unsafe.sendPacket(new StatusResponse(gson.toJson(pingResult.getResponse())));
|
||||
}
|
||||
}
|
||||
};
|
||||
InitialHandler.this.bungee.getPluginManager().callEvent(new ProxyPingEvent(InitialHandler.this, result, callback));
|
||||
}
|
||||
};
|
||||
if(forced != null && this.listener.isPingPassthrough()) {
|
||||
((BungeeServerInfo)forced).ping(pingBack, this.handshake.getProtocolVersion());
|
||||
} else {
|
||||
int protocol = net.md_5.bungee.protocol.Protocol.supportedVersions.contains(Integer.valueOf(this.handshake.getProtocolVersion()))?this.handshake.getProtocolVersion():this.bungee.getProtocolVersion();
|
||||
pingBack.done(new ServerPing(new Protocol(this.bungee.getName() + " " + this.bungee.getGameVersion(), protocol), new Players(this.listener.getMaxPlayers(), this.bungee.getOnlineCount(), (PlayerInfo[])null), motd, BungeeCord.getInstance().config.getFaviconObject()), (Throwable)null);
|
||||
}
|
||||
|
||||
this.thisState = InitialHandler.State.PING;
|
||||
}
|
||||
|
||||
public void handle(PingPacket ping) throws Exception {
|
||||
if (thisState == State.PING) return; // MINEPLEX
|
||||
Preconditions.checkState(this.thisState == InitialHandler.State.PING, "Not expecting PING");
|
||||
this.unsafe.sendPacket(ping);
|
||||
this.disconnect((String)"");
|
||||
}
|
||||
|
||||
public void handle(Handshake handshake) throws Exception {
|
||||
Preconditions.checkState(this.thisState == InitialHandler.State.HANDSHAKE, "Not expecting HANDSHAKE");
|
||||
this.handshake = handshake;
|
||||
this.ch.setVersion(handshake.getProtocolVersion());
|
||||
if(handshake.getHost().endsWith(".")) {
|
||||
handshake.setHost(handshake.getHost().substring(0, handshake.getHost().length() - 1));
|
||||
}
|
||||
|
||||
this.virtualHost = InetSocketAddress.createUnresolved(handshake.getHost(), handshake.getPort());
|
||||
this.bungee.getLogger().log(Level.INFO, "{0} has connected", this);
|
||||
this.bungee.getPluginManager().callEvent(new PlayerHandshakeEvent(this, handshake));
|
||||
switch(handshake.getRequestedProtocol()) {
|
||||
case 1:
|
||||
this.thisState = InitialHandler.State.STATUS;
|
||||
this.ch.setProtocol(net.md_5.bungee.protocol.Protocol.STATUS);
|
||||
break;
|
||||
case 2:
|
||||
this.thisState = InitialHandler.State.USERNAME;
|
||||
this.ch.setProtocol(net.md_5.bungee.protocol.Protocol.LOGIN);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Cannot request protocol " + handshake.getRequestedProtocol());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void handle(LoginRequest loginRequest) throws Exception {
|
||||
Preconditions.checkState(this.thisState == InitialHandler.State.USERNAME, "Not expecting USERNAME");
|
||||
this.loginRequest = loginRequest;
|
||||
if(!net.md_5.bungee.protocol.Protocol.supportedVersions.contains(Integer.valueOf(this.handshake.getProtocolVersion()))) {
|
||||
this.disconnect((String)this.bungee.getTranslation("outdated_server", new Object[0]));
|
||||
} else if(this.getName().contains(".")) {
|
||||
this.disconnect((String)this.bungee.getTranslation("name_invalid", new Object[0]));
|
||||
} else if(this.getName().length() > 16) {
|
||||
this.disconnect((String)this.bungee.getTranslation("name_too_long", new Object[0]));
|
||||
} else {
|
||||
int limit = BungeeCord.getInstance().config.getPlayerLimit();
|
||||
if(limit > 0 && this.bungee.getOnlineCount() > limit) {
|
||||
this.disconnect((String)this.bungee.getTranslation("proxy_full", new Object[0]));
|
||||
} else if(!this.isOnlineMode() && this.bungee.getPlayer(this.getName()) != null) {
|
||||
this.disconnect((String)this.bungee.getTranslation("already_connected", new Object[0]));
|
||||
} else {
|
||||
Callback callback = new Callback<PreLoginEvent>() {
|
||||
public void done(PreLoginEvent result, Throwable error) {
|
||||
if(result.isCancelled()) {
|
||||
InitialHandler.this.disconnect((String)result.getCancelReason());
|
||||
} else if(!InitialHandler.this.ch.isClosed()) {
|
||||
if(InitialHandler.this.onlineMode) {
|
||||
InitialHandler.this.unsafe().sendPacket(InitialHandler.this.request = EncryptionUtil.encryptRequest());
|
||||
} else {
|
||||
InitialHandler.this.finish();
|
||||
}
|
||||
|
||||
InitialHandler.this.thisState = InitialHandler.State.ENCRYPT;
|
||||
}
|
||||
}
|
||||
};
|
||||
this.bungee.getPluginManager().callEvent(new PreLoginEvent(this, callback));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(EncryptionResponse encryptResponse) throws Exception {
|
||||
Preconditions.checkState(this.thisState == InitialHandler.State.ENCRYPT, "Not expecting ENCRYPT");
|
||||
SecretKey sharedKey = EncryptionUtil.getSecret(encryptResponse, this.request);
|
||||
BungeeCipher decrypt = EncryptionUtil.getCipher(false, sharedKey);
|
||||
this.ch.addBefore("frame-decoder", "decrypt", new CipherDecoder(decrypt));
|
||||
BungeeCipher encrypt = EncryptionUtil.getCipher(true, sharedKey);
|
||||
this.ch.addBefore("frame-prepender", "encrypt", new CipherEncoder(encrypt));
|
||||
String encName = URLEncoder.encode(this.getName(), "UTF-8");
|
||||
MessageDigest sha = MessageDigest.getInstance("SHA-1");
|
||||
byte[][] encodedHash = new byte[][]{this.request.getServerId().getBytes("ISO_8859_1"), sharedKey.getEncoded(), EncryptionUtil.keys.getPublic().getEncoded()};
|
||||
int authURL = encodedHash.length;
|
||||
|
||||
for(int handler = 0; handler < authURL; ++handler) {
|
||||
byte[] bit = encodedHash[handler];
|
||||
sha.update(bit);
|
||||
}
|
||||
|
||||
String var11 = URLEncoder.encode((new BigInteger(sha.digest())).toString(16), "UTF-8");
|
||||
String var12 = "https://sessionserver.mojang.com/session/minecraft/hasJoined?username=" + encName + "&serverId=" + var11;
|
||||
Callback var13 = new Callback<String>() {
|
||||
public void done(String result, Throwable error) {
|
||||
if(error == null) {
|
||||
LoginResult obj = (LoginResult)BungeeCord.getInstance().gson.fromJson(result, LoginResult.class);
|
||||
if(obj != null) {
|
||||
InitialHandler.this.loginProfile = obj;
|
||||
InitialHandler.this.uniqueId = Util.getUUID(obj.getId());
|
||||
InitialHandler.this.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
InitialHandler.this.disconnect((String)"Not authenticated with Minecraft.net");
|
||||
} else {
|
||||
InitialHandler.this.disconnect((String)InitialHandler.this.bungee.getTranslation("mojang_fail", new Object[0]));
|
||||
InitialHandler.this.bungee.getLogger().log(Level.SEVERE, "Error authenticating " + InitialHandler.this.getName() + " with minecraft.net", error);
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
HttpClient.get(var12, this.ch.getHandle().eventLoop(), var13);
|
||||
}
|
||||
|
||||
private void finish() {
|
||||
ProxiedPlayer old = this.bungee.getPlayer(this.getName());
|
||||
if(old != null) {
|
||||
old.disconnect(this.bungee.getTranslation("already_connected", new Object[0]));
|
||||
}
|
||||
|
||||
this.offlineId = UUID.nameUUIDFromBytes(("OfflinePlayer:" + this.getName()).getBytes(Charsets.UTF_8));
|
||||
if(this.uniqueId == null) {
|
||||
this.uniqueId = this.offlineId;
|
||||
}
|
||||
|
||||
Callback complete = new Callback<LoginEvent>() {
|
||||
public void done(LoginEvent result, Throwable error) {
|
||||
if(result.isCancelled()) {
|
||||
InitialHandler.this.disconnect((String)result.getCancelReason());
|
||||
} else if(!InitialHandler.this.ch.isClosed()) {
|
||||
InitialHandler.this.ch.getHandle().eventLoop().execute(new Runnable() {
|
||||
public void run() {
|
||||
if(InitialHandler.this.ch.getHandle().isActive()) {
|
||||
if(InitialHandler.this.getVersion() >= 5) {
|
||||
InitialHandler.this.unsafe.sendPacket(new LoginSuccess(InitialHandler.this.getUniqueId().toString(), InitialHandler.this.getName()));
|
||||
} else {
|
||||
InitialHandler.this.unsafe.sendPacket(new LoginSuccess(InitialHandler.this.getUUID(), InitialHandler.this.getName()));
|
||||
}
|
||||
|
||||
InitialHandler.this.ch.setProtocol(net.md_5.bungee.protocol.Protocol.GAME);
|
||||
UserConnection userCon = new UserConnection(InitialHandler.this.bungee, InitialHandler.this.ch, InitialHandler.this.getName(), InitialHandler.this);
|
||||
userCon.init();
|
||||
InitialHandler.this.bungee.getPluginManager().callEvent(new PostLoginEvent(userCon));
|
||||
((HandlerBoss)InitialHandler.this.ch.getHandle().pipeline().get(HandlerBoss.class)).setHandler(new UpstreamBridge(InitialHandler.this.bungee, userCon));
|
||||
ServerInfo server;
|
||||
if(InitialHandler.this.bungee.getReconnectHandler() != null) {
|
||||
server = InitialHandler.this.bungee.getReconnectHandler().getServer(userCon);
|
||||
} else {
|
||||
server = AbstractReconnectHandler.getForcedHost(InitialHandler.this);
|
||||
}
|
||||
|
||||
if(server == null) {
|
||||
server = InitialHandler.this.bungee.getServerInfo(InitialHandler.this.listener.getDefaultServer());
|
||||
}
|
||||
|
||||
userCon.connect(server, (Callback)null, true);
|
||||
InitialHandler.this.thisState = InitialHandler.State.FINISHED;
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
this.bungee.getPluginManager().callEvent(new LoginEvent(this, complete));
|
||||
}
|
||||
|
||||
public void disconnect(String reason) {
|
||||
this.disconnect((BaseComponent[])TextComponent.fromLegacyText(reason));
|
||||
}
|
||||
|
||||
public void disconnect(final BaseComponent... reason) {
|
||||
if(!this.ch.isClosed()) {
|
||||
this.ch.getHandle().eventLoop().schedule(new Runnable() {
|
||||
public void run() {
|
||||
InitialHandler.this.unsafe().sendPacket(new Kick(ComponentSerializer.toString(reason)));
|
||||
InitialHandler.this.ch.close();
|
||||
}
|
||||
}, 500L, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void disconnect(BaseComponent reason) {
|
||||
this.disconnect((BaseComponent[])(new BaseComponent[]{reason}));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.loginRequest == null?null:this.loginRequest.getData();
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return this.handshake == null?-1:this.handshake.getProtocolVersion();
|
||||
}
|
||||
|
||||
public InetSocketAddress getAddress() {
|
||||
return (InetSocketAddress)this.ch.getHandle().remoteAddress();
|
||||
}
|
||||
|
||||
public Unsafe unsafe() {
|
||||
return this.unsafe;
|
||||
}
|
||||
|
||||
public void setOnlineMode(boolean onlineMode) {
|
||||
Preconditions.checkState(this.thisState == InitialHandler.State.USERNAME, "Can only set online mode status whilst state is username");
|
||||
this.onlineMode = onlineMode;
|
||||
}
|
||||
|
||||
public String getUUID() {
|
||||
return this.uniqueId.toString().replaceAll("-", "");
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "[" + (this.getName() != null?this.getName():this.getAddress()) + "] <-> InitialHandler";
|
||||
}
|
||||
|
||||
@ConstructorProperties({"bungee", "listener"})
|
||||
public InitialHandler(ProxyServer bungee, ListenerInfo listener) {
|
||||
this.thisState = InitialHandler.State.HANDSHAKE;
|
||||
this.unsafe = new Unsafe() {
|
||||
public void sendPacket(DefinedPacket packet) {
|
||||
InitialHandler.this.ch.write(packet);
|
||||
}
|
||||
};
|
||||
this.onlineMode = BungeeCord.getInstance().config.isOnlineMode();
|
||||
this.bungee = bungee;
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
public ListenerInfo getListener() {
|
||||
return this.listener;
|
||||
}
|
||||
|
||||
public Handshake getHandshake() {
|
||||
return this.handshake;
|
||||
}
|
||||
|
||||
public LoginRequest getLoginRequest() {
|
||||
return this.loginRequest;
|
||||
}
|
||||
|
||||
public List<PluginMessage> getRegisterMessages() {
|
||||
return this.registerMessages;
|
||||
}
|
||||
|
||||
public boolean isOnlineMode() {
|
||||
return this.onlineMode;
|
||||
}
|
||||
|
||||
public InetSocketAddress getVirtualHost() {
|
||||
return this.virtualHost;
|
||||
}
|
||||
|
||||
public UUID getUniqueId() {
|
||||
return this.uniqueId;
|
||||
}
|
||||
|
||||
public UUID getOfflineId() {
|
||||
return this.offlineId;
|
||||
}
|
||||
|
||||
public LoginResult getLoginProfile() {
|
||||
return this.loginProfile;
|
||||
}
|
||||
|
||||
public boolean isLegacy() {
|
||||
return this.legacy;
|
||||
}
|
||||
|
||||
public ChannelWrapper getChannelWrapper()
|
||||
{
|
||||
return ch; //MINEPLEX
|
||||
}
|
||||
|
||||
private static enum State {
|
||||
HANDSHAKE,
|
||||
STATUS,
|
||||
PING,
|
||||
USERNAME,
|
||||
ENCRYPT,
|
||||
FINISHED;
|
||||
|
||||
private State() {
|
||||
}
|
||||
}
|
||||
|
||||
public static void setCustomMotdFactory(CustomMotdFactory factory)
|
||||
{
|
||||
_customMotdFactory = factory;
|
||||
}
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
//
|
||||
// Source code recreated from a .class file by IntelliJ IDEA
|
||||
// (powered by Fernflower decompiler)
|
||||
//
|
||||
|
||||
package net.md_5.bungee.connection;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import net.md_5.bungee.BungeeCord;
|
||||
import net.md_5.bungee.api.Callback;
|
||||
import net.md_5.bungee.api.ProxyServer;
|
||||
import net.md_5.bungee.api.ServerPing;
|
||||
import net.md_5.bungee.api.config.ServerInfo;
|
||||
import net.md_5.bungee.netty.ChannelWrapper;
|
||||
import net.md_5.bungee.netty.PacketHandler;
|
||||
import net.md_5.bungee.protocol.MinecraftDecoder;
|
||||
import net.md_5.bungee.protocol.MinecraftEncoder;
|
||||
import net.md_5.bungee.protocol.Protocol;
|
||||
import net.md_5.bungee.protocol.packet.Handshake;
|
||||
import net.md_5.bungee.protocol.packet.StatusRequest;
|
||||
import net.md_5.bungee.protocol.packet.StatusResponse;
|
||||
|
||||
public class PingHandler extends PacketHandler {
|
||||
private final ServerInfo target;
|
||||
private final Callback<ServerPing> callback;
|
||||
private final int protocol;
|
||||
private ChannelWrapper channel;
|
||||
|
||||
public void connected(ChannelWrapper channel) throws Exception {
|
||||
this.channel = channel;
|
||||
MinecraftEncoder encoder = new MinecraftEncoder(Protocol.HANDSHAKE, false, this.protocol);
|
||||
channel.getHandle().pipeline().addAfter("frame-decoder", "packet-decoder", new MinecraftDecoder(Protocol.STATUS, false, ProxyServer.getInstance().getProtocolVersion()));
|
||||
channel.getHandle().pipeline().addAfter("frame-prepender", "packet-encoder", encoder);
|
||||
channel.write(new Handshake(this.protocol, this.target.getAddress().getHostString(), this.target.getAddress().getPort(), 1));
|
||||
encoder.setProtocol(Protocol.STATUS);
|
||||
channel.write(new StatusRequest());
|
||||
}
|
||||
|
||||
public void exception(Throwable t) throws Exception {
|
||||
this.callback.done(null, t);
|
||||
}
|
||||
|
||||
public void handle(StatusResponse statusResponse) throws Exception {
|
||||
Gson gson = this.protocol == 4?BungeeCord.getInstance().gsonLegacy:BungeeCord.getInstance().gson;
|
||||
this.callback.done(gson.fromJson(statusResponse.getResponse(), ServerPing.class), (Throwable)null);
|
||||
// this.channel.close(); //MINEPLEX
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "[Ping Handler] -> " + this.target.getName();
|
||||
}
|
||||
|
||||
public PingHandler(ServerInfo target, Callback<ServerPing> callback, int protocol) {
|
||||
this.target = target;
|
||||
this.callback = callback;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user