diff --git a/Bridge/pom.xml b/Bridge/pom.xml
new file mode 100644
index 0000000..696448e
--- /dev/null
+++ b/Bridge/pom.xml
@@ -0,0 +1,94 @@
+
+
+ 4.0.0
+ ASys Bridge
+ http://dmitriymx.ru/
+
+
+ UTF-8
+ 1.8
+ 1.8-SNAPSHOT
+ asys.bridge.Bridge
+
+
+ asys
+ bridge
+ 0.12
+ jar
+
+
+
+ bungee-repo
+ https://oss.sonatype.org/content/groups/public/
+
+
+
+
+
+ net.md-5
+ bungeecord-api
+ ${bungee.version}
+
+
+ asys.lib
+ protocol
+ 0.3
+
+
+
+
+ ${project.artifactId}-${project.version}
+
+
+ ${project.basedir}/src/main/resources
+
+ **
+
+ true
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.5.1
+
+ ${java.version}
+ ${java.version}
+ ${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 2.15
+
+ -Dfile.encoding=${project.build.sourceEncoding}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 1.6
+
+
+ package
+
+ shade
+
+
+
+
+ asys.lib:protocol
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Bridge/src/main/java/asys/bridge/Bridge.java b/Bridge/src/main/java/asys/bridge/Bridge.java
new file mode 100644
index 0000000..ce21f5e
--- /dev/null
+++ b/Bridge/src/main/java/asys/bridge/Bridge.java
@@ -0,0 +1,90 @@
+/*
+ * DmitriyMX
+ * 2016-08-24
+ */
+package asys.bridge;
+
+import asys.bridge.netty.Client;
+import net.md_5.bungee.api.plugin.Plugin;
+
+import java.io.IOException;
+import java.net.ConnectException;
+
+public class Bridge extends Plugin {
+ private Client netty;
+ private BungeeServerAPI serverAPI;
+
+ @Override
+ public void onEnable() {
+ try {
+ this.serverAPI = new BungeeServerAPI();
+ } catch (IOException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ new Thread(new WatchConnect(), "ASys Client").start();
+ }
+
+ @Override
+ public void onDisable() {
+ if (netty != null)
+ netty.disconnect();
+ }
+
+ public BungeeServerAPI getServerAPI() {
+ return serverAPI;
+ }
+
+ private class WatchConnect implements Runnable {
+ @Override
+ public void run() {
+ // Попытка первого подключения
+ // Если false, значит попытка соединения прервана из вне
+ if (!tryConnect()) return;
+
+ // Продолжаем следить за коннектом
+ while (netty != null) {
+ if (!netty.isConnected()) {
+ getLogger().warning("Lost connect! Try reconnect...");
+ // Если false, значит попытка соединения прервана из вне
+ if (!tryConnect()) return;
+ } else {
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+ }
+ }
+
+ // Если false, значит попытка соединения прервана из вне
+ private boolean tryConnect() {
+ netty = new Client("127.0.0.1", (short)6251, Bridge.this);
+
+ boolean _try = true;
+ do {
+ try {
+ netty.connect();
+ _try = false;
+ } catch (InterruptedException e) {
+ netty.disconnect();
+ netty = null;
+ return false;
+ } catch (ConnectException e) {
+ getLogger().warning(e.getMessage());
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e1) {
+ netty = null;
+ return false;
+ }
+ }
+ } while (_try);
+
+ getLogger().info("ASys connected");
+ return true;
+ }
+ }
+}
diff --git a/Bridge/src/main/java/asys/bridge/BungeeServerAPI.java b/Bridge/src/main/java/asys/bridge/BungeeServerAPI.java
new file mode 100644
index 0000000..3790f35
--- /dev/null
+++ b/Bridge/src/main/java/asys/bridge/BungeeServerAPI.java
@@ -0,0 +1,74 @@
+/*
+ * DmitriyMX
+ * 2016-08-26
+ */
+package asys.bridge;
+
+import net.md_5.bungee.api.ProxyServer;
+import net.md_5.bungee.api.config.ServerInfo;
+import net.md_5.bungee.api.connection.ProxiedPlayer;
+import net.md_5.bungee.config.Configuration;
+import net.md_5.bungee.config.YamlConfiguration;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.Map;
+
+public class BungeeServerAPI {
+ private File file;
+ private Configuration bungeeConfig;
+
+ public BungeeServerAPI() throws IOException {
+ file = new File(ProxyServer.getInstance().getPluginsFolder().getParentFile(), "config.yml");
+ bungeeConfig = YamlConfiguration.getProvider(YamlConfiguration.class).load(file);
+ }
+
+ public boolean addServer(String name, String address) {
+ if (getServers().get(name) != null) return false;
+
+ String[] addrPort = address.split(":",2);
+ InetSocketAddress ipAddress = new InetSocketAddress(addrPort[0], Integer.valueOf(addrPort[1]));
+
+ ServerInfo serverInfo = ProxyServer.getInstance().constructServerInfo(name, ipAddress, "", false);
+ getServers().put(serverInfo.getName(), serverInfo);
+
+ bungeeConfig.set("servers." + serverInfo.getName() + ".motd", serverInfo.getMotd());
+ bungeeConfig.set("servers." + serverInfo.getName() + ".address", serverInfo.getAddress().getAddress().getHostAddress() + ":" + serverInfo.getAddress().getPort());
+ bungeeConfig.set("servers." + serverInfo.getName() + ".restricted", false);
+
+ try {
+ YamlConfiguration.getProvider(YamlConfiguration.class).save(bungeeConfig, file);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
+ public boolean removeServer(String name) {
+ ServerInfo serverInfo = getServers().get(name);
+ if (serverInfo == null) return false;
+
+ //TODO не совсем корректно...
+ for (ProxiedPlayer player : serverInfo.getPlayers()) {
+ player.connect(getServers().get(player.getPendingConnection().getListener().getFallbackServer()));
+ }
+
+ getServers().remove(name);
+
+ bungeeConfig.set("servers." + name, null);
+
+ try {
+ YamlConfiguration.getProvider(YamlConfiguration.class).save(bungeeConfig, file);
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return true;
+ }
+
+ private Map getServers() {
+ return ProxyServer.getInstance().getServers();
+ }
+}
diff --git a/Bridge/src/main/java/asys/bridge/netty/Client.java b/Bridge/src/main/java/asys/bridge/netty/Client.java
new file mode 100644
index 0000000..39763fc
--- /dev/null
+++ b/Bridge/src/main/java/asys/bridge/netty/Client.java
@@ -0,0 +1,72 @@
+/*
+ * DmitriyMX
+ * 2016-08-24
+ */
+package asys.bridge.netty;
+
+import asys.bridge.Bridge;
+import asys.lib.protocol.PacketDecoder;
+import asys.lib.protocol.PacketEncoder;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.Channel;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelPipeline;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+
+import java.net.ConnectException;
+
+public class Client {
+ private String host;
+ private short port;
+ private Bridge bridge;
+ private EventLoopGroup group;
+ private Channel channel;
+
+ public Client(String host, short port, Bridge bridge) {
+ this.host = host;
+ this.port = port;
+ this.bridge = bridge;
+ }
+
+ public void connect() throws InterruptedException, ConnectException {
+ group = new NioEventLoopGroup();
+
+ Bootstrap bootstrap = prepare_Bootstrap();
+ channel = bootstrap.connect(host, port).sync().channel();
+ channel.closeFuture();
+ }
+
+ private Bootstrap prepare_Bootstrap() {
+ Bootstrap bootstrap = new Bootstrap();
+ bootstrap.group(group)
+ .channel(NioSocketChannel.class)
+ .handler(prepare_ChannelInitializer());
+
+ return bootstrap;
+ }
+
+ private ChannelInitializer prepare_ChannelInitializer() {
+ return new ChannelInitializer() {
+ @Override
+ protected void initChannel(SocketChannel channel) throws Exception {
+ ChannelPipeline pipeline = channel.pipeline();
+ pipeline.addLast(
+ new PacketEncoder(),
+ new PacketDecoder(),
+ new ClientHandler(bridge)
+ );
+ }
+ };
+ }
+
+ public void disconnect() {
+ group.shutdownGracefully();
+ }
+
+ public boolean isConnected() {
+ return channel.isOpen();
+ }
+}
diff --git a/Bridge/src/main/java/asys/bridge/netty/ClientHandler.java b/Bridge/src/main/java/asys/bridge/netty/ClientHandler.java
new file mode 100644
index 0000000..a695149
--- /dev/null
+++ b/Bridge/src/main/java/asys/bridge/netty/ClientHandler.java
@@ -0,0 +1,47 @@
+/*
+ * DmitriyMX
+ * 2016-08-21
+ */
+package asys.bridge.netty;
+
+import asys.bridge.Bridge;
+import asys.lib.protocol.Packet;
+import asys.lib.protocol.ServerInfoPacket;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.SimpleChannelInboundHandler;
+
+public class ClientHandler extends SimpleChannelInboundHandler {
+ private Bridge bridge;
+
+ public ClientHandler(Bridge bridge) {
+ this.bridge = bridge;
+ }
+
+ @Override
+ public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
+ cause.printStackTrace();
+ ctx.close();
+ }
+
+ @Override
+ protected void channelRead0(ChannelHandlerContext channelHandlerContext, Packet packet) throws Exception {
+ ServerInfoPacket infoPacket = (ServerInfoPacket)packet;
+
+ if (infoPacket.getState() == 1) {
+ boolean result = bridge.getServerAPI().addServer(infoPacket.getServerId(), infoPacket.getAddress());
+ if (result) bridge.getLogger().info(String.format("Add server '%s'", infoPacket.getServerId()));
+ else bridge.getLogger().warning(String.format("Server '%s' can't adding", infoPacket.getServerId()));
+ } else if (infoPacket.getState() == 0) {
+ boolean result = bridge.getServerAPI().removeServer(infoPacket.getServerId());
+ if (result) bridge.getLogger().info(String.format("Remove server '%s'", infoPacket.getServerId()));
+ else bridge.getLogger().warning(String.format("Server '%s' can't removing", infoPacket.getServerId()));
+ }
+
+ bridge.getLogger().config(String.format(
+ "Incomming packet: %d | %s | %s",
+ infoPacket.getState(),
+ infoPacket.getServerId(),
+ (infoPacket.getState() == 1 ? infoPacket.getAddress() : "")
+ ));
+ }
+}
diff --git a/Bridge/src/main/resources/bungee.yml b/Bridge/src/main/resources/bungee.yml
new file mode 100644
index 0000000..4cfc632
--- /dev/null
+++ b/Bridge/src/main/resources/bungee.yml
@@ -0,0 +1,3 @@
+name: ASysBridge
+main: ${bungee.mainclass}
+version: ${project.version}
\ No newline at end of file