├── src └── main │ ├── resources │ ├── plugin.yml │ ├── config.yml │ └── default.lang │ └── java │ └── net │ └── bridgesapis │ └── bungeebridge │ ├── core │ ├── PendingTask.java │ ├── handlers │ │ ├── PubSubConsumer.java │ │ ├── SubscribingThread.java │ │ ├── ApiExecutor.java │ │ └── MainSubscriber.java │ ├── players │ │ ├── InvalidTypeException.java │ │ ├── NameFetcher.java │ │ ├── PlayerDataManager.java │ │ ├── PlayerData.java │ │ ├── UUIDFetcher.java │ │ ├── PlayerDataAbstract.java │ │ └── UUIDTranslator.java │ ├── TasksExecutor.java │ ├── servers │ │ ├── Subscriber.java │ │ └── ServersManager.java │ ├── database │ │ ├── DatabaseConnector.java │ │ ├── Publisher.java │ │ ├── ServerSettings.java │ │ ├── SentinelDatabaseConnector.java │ │ └── SingleDatabaseConnector.java │ └── proxies │ │ ├── Subscriber.java │ │ ├── NetworkBridge.java │ │ └── BridgeListener.java │ ├── services │ ├── Service.java │ ├── IChatListener.java │ ├── ServiceManager.java │ └── IFriendsManagement.java │ ├── i18n │ ├── TranslatorComponentBuilder.java │ ├── TranslatorComponent.java │ └── I18n.java │ ├── commands │ ├── GlobalMessagesHandler.java │ ├── CommandProxyDebug.java │ ├── DefaultExecutor.java │ ├── CommandDelAutoMessage.java │ ├── CommandGlobal.java │ ├── CommandDispatch.java │ ├── CommandSetOption.java │ ├── CommandHelp.java │ ├── CommandSetAutoMessage.java │ ├── CommandGlist.java │ └── CommandLocation.java │ ├── permissions │ ├── VirtPlayer.java │ ├── commands │ │ ├── CommandRefresh.java │ │ ├── CommandUsers.java │ │ └── CommandGroups.java │ ├── PlayerListener.java │ └── PermissionsBridge.java │ ├── listeners │ ├── ServerMovementsListener.java │ └── PlayerJoinEvent.java │ ├── utils │ ├── UnknownPlayer.java │ ├── Misc.java │ ├── SettingsManager.java │ └── TeleportTools.java │ └── BungeeBridge.java ├── CONTRIBUTE.MD ├── README.MD ├── PROTOCOL.MD └── pom.xml /src/main/resources/plugin.yml: -------------------------------------------------------------------------------- 1 | name: BungeeBridge 2 | main: net.bridgesapis.bungeebridge.BungeeBridge 3 | author: zyuiop 4 | version: 0.1 -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/PendingTask.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.core; 2 | 3 | public interface PendingTask { 4 | 5 | public void run(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/services/Service.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.services; 2 | 3 | /** 4 | * @author zyuiop 5 | */ 6 | public interface Service { 7 | } 8 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/handlers/PubSubConsumer.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.core.handlers; 2 | 3 | public interface PubSubConsumer { 4 | public void consume(String channel, String message); 5 | } 6 | -------------------------------------------------------------------------------- /CONTRIBUTE.MD: -------------------------------------------------------------------------------- 1 | Comment contribuer ? 2 | ==================== 3 | 4 | ## Objectifs du projet : 5 | 6 | Les objectifs du projet sont de fournir une plateforme fiable et complète de communications entre proxies BungeeCord. 7 | 8 | ## Objectifs : 9 | 10 | - Se séparer des messages liés à l'ancienne provenance du plugin 11 | - Implémenter un système i18n 12 | - Permettre l'utilisation d'un Jedis simple, pas en Sentinel 13 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/players/InvalidTypeException.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.core.players; 2 | 3 | public class InvalidTypeException extends IllegalArgumentException { 4 | public InvalidTypeException() { 5 | } 6 | 7 | public InvalidTypeException(String s) { 8 | super(s); 9 | } 10 | 11 | public InvalidTypeException(String message, Throwable cause) { 12 | super(message, cause); 13 | } 14 | 15 | public InvalidTypeException(Throwable cause) { 16 | super(cause); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/services/IChatListener.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.services; 2 | 3 | import java.util.Date; 4 | import java.util.UUID; 5 | 6 | /** 7 | * @author zyuiop 8 | */ 9 | public interface IChatListener extends Service { 10 | void addMute(UUID id, Date end, String reason); 11 | 12 | void removeMute(UUID id); 13 | 14 | boolean isMuted(UUID id); 15 | 16 | String getReason(UUID id); 17 | 18 | Date getEnd(UUID id); 19 | 20 | void consume(String channel, String message); 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/TasksExecutor.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.core; 2 | 3 | import java.util.concurrent.LinkedBlockingQueue; 4 | 5 | public class TasksExecutor implements Runnable { 6 | 7 | private LinkedBlockingQueue pending = new LinkedBlockingQueue<>(); 8 | 9 | public void addTask(PendingTask message) { 10 | pending.add(message); 11 | } 12 | 13 | @Override 14 | public void run() { 15 | while (true) { 16 | try { 17 | pending.take().run(); 18 | } catch (Exception e) { 19 | e.printStackTrace(); 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/main/resources/config.yml: -------------------------------------------------------------------------------- 1 | proxy: 2 | name: Proxy1 3 | 4 | # Default lang is french 5 | lang: default 6 | 7 | database: 8 | sentinels: [] # Sentinels IP:PORT 9 | auth: "" # Authentification key (same for both databases) 10 | mastername: "" # A database which will be used to store permanent data 11 | cachemastername: "" # A database which will be used to store temporary data. you can use the same as master name (not tested, shall work) 12 | 13 | # If you prefear to use a classic Redis network, uncomment the following lines. 14 | 15 | #singleredis: 16 | # auth: "" #Authentication 17 | # masterhost: "" # IP:PORT of the master 18 | # cachehost: "" # IP:PORT of the cache db 19 | 20 | # Default permissions group name 21 | defaultGroup: Joueur -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/i18n/TranslatorComponentBuilder.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.i18n; 2 | 3 | import net.md_5.bungee.api.chat.ComponentBuilder; 4 | 5 | /** 6 | * Created by zyuiop on 26/05/15. 7 | * Licensed under GNU LGPL license 8 | */ 9 | public class TranslatorComponentBuilder extends ComponentBuilder { 10 | public TranslatorComponentBuilder(String text) { 11 | super(I18n.getTranslation(text)); 12 | } 13 | 14 | public ComponentBuilder appendTranslatedText(String text) { 15 | return super.append(I18n.getTranslation(text)); 16 | } 17 | 18 | public ComponentBuilder appendTranslatedText(String text, FormatRetention retention) { 19 | return super.append(I18n.getTranslation(text), retention); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/commands/GlobalMessagesHandler.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.commands; 2 | 3 | import net.bridgesapis.bungeebridge.core.handlers.PubSubConsumer; 4 | import net.bridgesapis.bungeebridge.i18n.I18n; 5 | import net.md_5.bungee.api.ChatColor; 6 | import net.md_5.bungee.api.ProxyServer; 7 | import net.md_5.bungee.api.chat.TextComponent; 8 | import org.apache.commons.lang3.StringUtils; 9 | 10 | public class GlobalMessagesHandler implements PubSubConsumer { 11 | @Override 12 | public void consume(String channel, String message) { 13 | String sentBy = StringUtils.split(channel, ".")[1]; 14 | 15 | TextComponent sender = new TextComponent(I18n.getTranslation("global_prefix").replace("%NAME%", sentBy).replace("%MESSAGE%", message)); 16 | ProxyServer.getInstance().broadcast(sender); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/services/ServiceManager.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.services; 2 | 3 | import java.util.HashMap; 4 | 5 | /** 6 | * @author zyuiop 7 | */ 8 | public class ServiceManager { 9 | protected static HashMap, Service> serviceHashMap = new HashMap<>(); 10 | 11 | public static void registerService(Class serviceInterface, T serviceInstance) { 12 | serviceHashMap.put(serviceInterface, serviceInstance); 13 | } 14 | 15 | public static T getService(Class serviceInterface) { 16 | return (T) serviceHashMap.get(serviceInterface); 17 | } 18 | 19 | public static boolean hasService(Class serviceInterface) { 20 | return serviceHashMap.containsKey(serviceInterface); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/i18n/TranslatorComponent.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.i18n; 2 | 3 | import net.md_5.bungee.api.chat.BaseComponent; 4 | import net.md_5.bungee.api.chat.TextComponent; 5 | 6 | /** 7 | * Created by zyuiop on 26/05/15. 8 | * Licensed under GNU LGPL license 9 | */ 10 | public class TranslatorComponent extends TextComponent { 11 | public TranslatorComponent(TextComponent textComponent) { 12 | super(textComponent); 13 | } 14 | 15 | public TranslatorComponent(BaseComponent... extras) { 16 | super(extras); 17 | } 18 | 19 | public TranslatorComponent(String text) { 20 | super(I18n.getTranslation(text)); 21 | } 22 | 23 | public void setTranslatedText(String text) { 24 | super.setText(I18n.getTranslation(text)); 25 | } 26 | 27 | public void addTranslatedExtra(String text) { 28 | super.addExtra(I18n.getTranslation(text)); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/servers/Subscriber.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.core.servers; 2 | 3 | import redis.clients.jedis.JedisPubSub; 4 | 5 | public class Subscriber extends JedisPubSub { 6 | 7 | private final ServersManager bridge; 8 | 9 | public Subscriber(ServersManager bridge) { 10 | this.bridge = bridge; 11 | } 12 | 13 | @Override 14 | public void onMessage(String channel, String message) { 15 | String[] content = message.split(" "); 16 | if (content[0].equalsIgnoreCase("heartbeat")) { 17 | if (content.length < 3) 18 | return; 19 | 20 | String name = content[1]; 21 | String ip = content[2]; 22 | String port = content[3]; 23 | bridge.heartBeet(name, ip, port); 24 | } else if (content[0].equalsIgnoreCase("stop")) { 25 | if (content.length < 1) 26 | return; 27 | 28 | String name = content[1]; 29 | bridge.remove(name); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/commands/CommandProxyDebug.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.commands; 2 | 3 | import net.md_5.bungee.api.ChatColor; 4 | import net.md_5.bungee.api.CommandSender; 5 | import net.md_5.bungee.api.chat.ComponentBuilder; 6 | import net.bridgesapis.bungeebridge.BungeeBridge; 7 | 8 | 9 | /** 10 | * This file is a part of the SamaGames project 11 | * This code is absolutely confidential. 12 | * Created by zyuiop 13 | * (C) Copyright Elydra Network 2015 14 | * All rights reserved. 15 | */ 16 | public class CommandProxyDebug extends DefaultExecutor { 17 | 18 | private final BungeeBridge plugin; 19 | 20 | public CommandProxyDebug(BungeeBridge plugin) { 21 | super("proxydebug", "proxies.debug", "pdebug"); 22 | this.plugin = plugin; 23 | } 24 | 25 | @Override 26 | public void execute(CommandSender commandSender, String[] strings) { 27 | plugin.getConnector().getCommandsSubscriber().toggle(commandSender); 28 | commandSender.sendMessage(new ComponentBuilder("Debug updated.").color(ChatColor.GREEN).create()); 29 | } 30 | 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/services/IFriendsManagement.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.services; 2 | 3 | import java.util.ArrayList; 4 | import java.util.Date; 5 | import java.util.HashMap; 6 | import java.util.UUID; 7 | 8 | /** 9 | * @author zyuiop 10 | */ 11 | public interface IFriendsManagement extends Service { 12 | String sendRequest(UUID from, UUID add); 13 | 14 | boolean isFriend(UUID from, UUID isFriend); 15 | 16 | String grantRequest(UUID from, UUID add); 17 | 18 | String denyRequest(UUID from, UUID add); 19 | 20 | String removeFriend(UUID asking, UUID askTo); 21 | 22 | ArrayList friendList(UUID asking); 23 | 24 | ArrayList UUIDFriendList(UUID asking); 25 | 26 | HashMap associatedFriendsList(UUID asking); 27 | 28 | HashMap onlineAssociatedFriendsList(UUID asking); 29 | 30 | ArrayList requestsList(UUID asking); 31 | 32 | ArrayList sentRequestsList(UUID asking); 33 | 34 | void request(UUID from, UUID to, Date date); 35 | 36 | void response(UUID from, UUID to, boolean accepted); 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/commands/DefaultExecutor.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.commands; 2 | 3 | import net.md_5.bungee.api.CommandSender; 4 | import net.md_5.bungee.api.plugin.Command; 5 | import net.md_5.bungee.api.plugin.TabExecutor; 6 | import net.bridgesapis.bungeebridge.BungeeBridge; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | import java.util.stream.Collectors; 11 | 12 | public abstract class DefaultExecutor extends Command implements TabExecutor { 13 | public DefaultExecutor(String name) { 14 | super(name); 15 | } 16 | 17 | public DefaultExecutor(String name, String permission, String... aliases) { 18 | super(name, permission, aliases); 19 | } 20 | 21 | @Override 22 | public java.lang.Iterable onTabComplete(CommandSender sender, String[] args) { 23 | List result = new ArrayList<>(); 24 | 25 | if(args.length < 1) { 26 | return result; 27 | } 28 | 29 | result.addAll(BungeeBridge.getInstance().getNetworkBridge().getOnlinePlayersNames().stream().filter(name -> name.toLowerCase().startsWith(args[0].toLowerCase())).collect(Collectors.toList())); 30 | 31 | return result; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/permissions/VirtPlayer.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.permissions; 2 | 3 | import net.md_5.bungee.api.ProxyServer; 4 | import net.md_5.bungee.api.connection.ProxiedPlayer; 5 | import net.zyuiop.crosspermissions.api.rawtypes.RawPlayer; 6 | 7 | import java.util.ArrayList; 8 | import java.util.UUID; 9 | 10 | public class VirtPlayer implements RawPlayer { 11 | 12 | private UUID playerId; 13 | private ProxiedPlayer player; 14 | 15 | public VirtPlayer(UUID id) { 16 | this.player = ProxyServer.getInstance().getPlayer(id); 17 | this.playerId = id; 18 | } 19 | 20 | @Override 21 | public void setPermission(String s, boolean b) { 22 | if (player != null) 23 | player.setPermission(s, b); 24 | } 25 | 26 | @Override 27 | public UUID getUniqueId() { 28 | return playerId; 29 | } 30 | 31 | @Override 32 | public void clearPermissions() { 33 | if (player != null) { 34 | ArrayList perms = new ArrayList<>(); 35 | for (String perm : player.getPermissions()) 36 | perms.add(perm); 37 | 38 | for (String perm : perms) 39 | player.setPermission(perm, false); // Conflits ? Possible. 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/commands/CommandDelAutoMessage.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.commands; 2 | 3 | import net.bridgesapis.bungeebridge.BungeeBridge; 4 | import net.bridgesapis.bungeebridge.i18n.I18n; 5 | import net.md_5.bungee.api.ChatColor; 6 | import net.md_5.bungee.api.CommandSender; 7 | import net.md_5.bungee.api.chat.TextComponent; 8 | import net.md_5.bungee.api.connection.ProxiedPlayer; 9 | import net.md_5.bungee.api.plugin.Command; 10 | import redis.clients.jedis.Jedis; 11 | 12 | public class CommandDelAutoMessage extends Command { 13 | 14 | public CommandDelAutoMessage() { 15 | super("delautomessage", "automessage.del", "dam"); 16 | } 17 | 18 | @Override 19 | public void execute(CommandSender arg0, String[] args) { 20 | 21 | ProxiedPlayer p = (ProxiedPlayer) arg0; 22 | if (!p.hasPermission("automessage.del")) { 23 | TextComponent c = new TextComponent(I18n.getTranslation("permission_denied")); 24 | c.setColor(ChatColor.RED); 25 | p.sendMessage(c); 26 | } else { 27 | Jedis jedis = BungeeBridge.getInstance().getConnector().getResource(); 28 | jedis.del("automessage"); 29 | jedis.close(); 30 | 31 | TextComponent c = new TextComponent(I18n.getTranslation("automessage_removed")); 32 | c.setColor(ChatColor.GREEN); 33 | p.sendMessage(c); 34 | } 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/listeners/ServerMovementsListener.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.listeners; 2 | 3 | import net.bridgesapis.bungeebridge.BungeeBridge; 4 | import net.md_5.bungee.api.ProxyServer; 5 | import net.md_5.bungee.api.config.ServerInfo; 6 | import net.md_5.bungee.api.event.ServerKickEvent; 7 | import net.md_5.bungee.api.plugin.Listener; 8 | import net.md_5.bungee.event.EventHandler; 9 | 10 | public class ServerMovementsListener implements Listener { 11 | 12 | protected BungeeBridge plugin; 13 | 14 | public ServerMovementsListener(BungeeBridge plugin) { 15 | this.plugin = plugin; 16 | } 17 | 18 | /** 19 | * Avoid the player to be kicked from the proxy when kicked from a game 20 | * @param event The ServerKickEvent 21 | */ 22 | @EventHandler 23 | public void onPlayerKick(ServerKickEvent event) { 24 | event.getPlayer().sendMessage(event.getKickReasonComponent()); 25 | event.setCancelled(true); 26 | 27 | if (event.getState() == ServerKickEvent.State.CONNECTING) { 28 | ProxyServer.getInstance().getLogger().info("[Server '" + event.getKickedFrom().getName() + "' refused connection] "+event.getPlayer().getDisplayName() + ", reason " + event.getKickReasonComponent()[0].toPlainText()); 29 | ServerInfo server = event.getPlayer().getServer().getInfo(); 30 | event.setCancelServer(server); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/utils/UnknownPlayer.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.utils; 2 | 3 | import java.util.UUID; 4 | 5 | public class UnknownPlayer { 6 | 7 | private UUID playerId; 8 | private String playerName; 9 | 10 | public UnknownPlayer(UUID playerId, String playerName) { 11 | this.playerId = playerId; 12 | this.playerName = playerName; 13 | } 14 | 15 | public UnknownPlayer() { 16 | 17 | } 18 | 19 | public UnknownPlayer(UUID playerId) { 20 | this.playerId = playerId; 21 | } 22 | 23 | public UUID getPlayerId() { 24 | return playerId; 25 | } 26 | 27 | public void setPlayerId(UUID playerId) { 28 | this.playerId = playerId; 29 | } 30 | 31 | public String getPlayerName() { 32 | return playerName; 33 | } 34 | 35 | public void setPlayerName(String playerName) { 36 | this.playerName = playerName; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return playerId+"|"+playerName; 42 | } 43 | 44 | @Override 45 | public boolean equals(Object compare) { 46 | if (compare instanceof UnknownPlayer) 47 | return ((UnknownPlayer) compare).getPlayerId().equals(playerId); 48 | else if (compare instanceof UUID) 49 | return ((UUID) compare).equals(playerId); 50 | else 51 | return false; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/database/DatabaseConnector.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.core.database; 2 | 3 | import net.bridgesapis.bungeebridge.BungeeBridge; 4 | import net.bridgesapis.bungeebridge.core.handlers.MainSubscriber; 5 | import net.bridgesapis.bungeebridge.core.handlers.PubSubConsumer; 6 | import net.bridgesapis.bungeebridge.core.handlers.SubscribingThread; 7 | import redis.clients.jedis.Jedis; 8 | 9 | /** 10 | * Created by zyuiop on 22/05/15. 11 | * Licensed under GNU LGPL license 12 | */ 13 | public abstract class DatabaseConnector { 14 | 15 | protected String password; 16 | protected BungeeBridge plugin; 17 | protected MainSubscriber commandsSubscriber; 18 | protected SubscribingThread thread; 19 | 20 | public void subscribe(String channel, PubSubConsumer consummer) { 21 | commandsSubscriber.subscribe(channel); 22 | commandsSubscriber.addConsumer(channel, consummer); 23 | } 24 | 25 | public void psubscribe(String channel, PubSubConsumer consummer) { 26 | commandsSubscriber.psubscribe(channel); 27 | commandsSubscriber.addPConsumer(channel, consummer); 28 | } 29 | 30 | public abstract Jedis getResource(); 31 | 32 | public abstract Jedis getBungeeResource(); 33 | 34 | public abstract void killConnections(); 35 | 36 | public abstract void initiateConnections() throws InterruptedException; 37 | 38 | public abstract MainSubscriber getCommandsSubscriber(); 39 | 40 | public abstract void disable(); 41 | } 42 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/permissions/commands/CommandRefresh.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.permissions.commands; 2 | 3 | import net.md_5.bungee.api.ChatColor; 4 | import net.md_5.bungee.api.CommandSender; 5 | import net.md_5.bungee.api.connection.ProxiedPlayer; 6 | import net.md_5.bungee.api.plugin.Command; 7 | import net.zyuiop.crosspermissions.api.PermissionsAPI; 8 | import net.zyuiop.crosspermissions.api.permissions.PermissionUser; 9 | 10 | public class CommandRefresh extends Command { 11 | 12 | private PermissionsAPI api; 13 | 14 | public CommandRefresh(PermissionsAPI api) { 15 | super("refresh"); 16 | this.api = api; 17 | } 18 | 19 | protected boolean canDo(CommandSender sender) { 20 | if (sender instanceof ProxiedPlayer) { 21 | PermissionUser u = api.getUser(((ProxiedPlayer) sender).getUniqueId()); 22 | if (u.hasPermission("permissions.bungee.*") || u.hasPermission("permissions.*") || u.hasPermission("permissions.bungee.refresh")) 23 | return true; 24 | return false; 25 | } else { 26 | return true; 27 | } 28 | } 29 | 30 | @Override 31 | public void execute(CommandSender sender, String[] args) { 32 | if (!canDo(sender)) { 33 | sender.sendMessage(ChatColor.RED + "Vous n'avez pas le droit de faire cela."); 34 | return; 35 | } 36 | api.getManager().refresh(); 37 | sender.sendMessage(ChatColor.GREEN + "Le cache a bien été rechargé."); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/commands/CommandGlobal.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.commands; 2 | 3 | import net.bridgesapis.bungeebridge.i18n.I18n; 4 | import net.bridgesapis.bungeebridge.i18n.TranslatorComponent; 5 | import net.md_5.bungee.api.ChatColor; 6 | import net.md_5.bungee.api.CommandSender; 7 | import net.md_5.bungee.api.chat.TextComponent; 8 | import net.md_5.bungee.api.connection.ProxiedPlayer; 9 | import net.md_5.bungee.api.plugin.Command; 10 | import net.bridgesapis.bungeebridge.BungeeBridge; 11 | import net.bridgesapis.bungeebridge.core.database.Publisher; 12 | import org.apache.commons.lang3.StringUtils; 13 | 14 | import java.util.Arrays; 15 | 16 | public class CommandGlobal extends Command { 17 | 18 | private final BungeeBridge plugin; 19 | 20 | public CommandGlobal(BungeeBridge plugin) { 21 | super("global", "modo.globalcomand", "glob"); 22 | this.plugin = plugin; 23 | } 24 | 25 | @Override 26 | public void execute(CommandSender arg0, String[] arg1) { 27 | 28 | ProxiedPlayer p = (ProxiedPlayer) arg0; 29 | if (!p.hasPermission("modo.globalcomand")) { 30 | TextComponent c = new TextComponent(I18n.getTranslation("permission_denied")); 31 | c.setColor(ChatColor.RED); 32 | p.sendMessage(c); 33 | } else if (arg1.length < 1) { 34 | TextComponent c = new TranslatorComponent("commands.global.not_sent"); 35 | c.setColor(ChatColor.RED); 36 | p.sendMessage(c); 37 | } else { 38 | plugin.getPublisher().publish(new Publisher.PendingMessage("globmessages." + arg0.getName(), StringUtils.join(Arrays.copyOfRange(arg1, 0, arg1.length), " "))); 39 | } 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/permissions/PlayerListener.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.permissions; 2 | 3 | import net.md_5.bungee.api.event.LoginEvent; 4 | import net.md_5.bungee.api.event.PostLoginEvent; 5 | import net.md_5.bungee.api.plugin.Listener; 6 | import net.md_5.bungee.event.EventHandler; 7 | import net.md_5.bungee.event.EventPriority; 8 | import net.bridgesapis.bungeebridge.BungeeBridge; 9 | 10 | import java.util.concurrent.TimeUnit; 11 | 12 | public class PlayerListener implements Listener { 13 | 14 | private PermissionsBridge bridge; 15 | private BungeeBridge plugin; 16 | 17 | public PlayerListener(PermissionsBridge bridge, BungeeBridge plugin) { 18 | this.bridge = bridge; 19 | this.plugin = plugin; 20 | } 21 | 22 | @EventHandler 23 | public void onLogin(final PostLoginEvent e) { 24 | plugin.getProxy().getScheduler().schedule(plugin, () -> { 25 | bridge.getApi().getManager().refreshPerms(e.getPlayer().getUniqueId()); 26 | bridge.logInfo("[PostLoginEvent] Applied permissions for player " + e.getPlayer().getUniqueId()); 27 | }, 2, TimeUnit.SECONDS); 28 | bridge.logInfo("[PostLoginEvent] Registered schedule for " + e.getPlayer().getUniqueId()); 29 | } 30 | 31 | @EventHandler(priority = EventPriority.LOWEST) 32 | public void onLogin(LoginEvent e) { 33 | e.registerIntent(plugin); 34 | bridge.logInfo("[PreLoginEvent] Loading permissions for player " + e.getConnection().getUniqueId()); 35 | bridge.getApi().getManager().getUser(e.getConnection().getUniqueId()); // On charge les permisisons 36 | e.completeIntent(plugin); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/utils/Misc.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.utils; 2 | 3 | import java.util.Calendar; 4 | import java.util.Date; 5 | 6 | public class Misc { 7 | public static String formatTime(long time) { 8 | int days = (int) time / (3600*24); 9 | int remainder = (int) time - days * (3600*24); 10 | int hours = remainder / 3600; 11 | remainder = remainder - (hours * 3600); 12 | int mins = remainder / 60; 13 | 14 | String ret = ""; 15 | if (days > 0) { 16 | ret+= days+" jours "; 17 | } 18 | 19 | if (hours > 0) { 20 | ret += hours+" heures "; 21 | } 22 | 23 | if (mins > 0) { 24 | ret += mins+" minutes "; 25 | } 26 | 27 | if (ret.equals("") && mins == 0) 28 | ret += "moins d'une minute"; 29 | 30 | return ret; 31 | } 32 | 33 | public static Date parseTime(String str) { 34 | Calendar cal = Calendar.getInstance(); // creates calendar 35 | cal.setTime(new Date()); // sets calendar time/date 36 | for (String t : str.split("\\+")) { 37 | String[] end = t.split(":"); 38 | int type; 39 | if (end[1].equalsIgnoreCase("d")) 40 | type = Calendar.DAY_OF_YEAR; 41 | else if (end[1].equalsIgnoreCase("h")) 42 | type = Calendar.HOUR; 43 | else if (end[1].equalsIgnoreCase("m")) 44 | type = Calendar.MINUTE; 45 | else 46 | type = Calendar.SECOND; 47 | cal.add(type, Integer.parseInt(end[0])); 48 | } 49 | return cal.getTime(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/players/NameFetcher.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright © 2013 tuxed 3 | * This work is free. You can redistribute it and/or modify it under the 4 | * terms of the Do What The Fuck You Want To Public License, Version 2, 5 | * as published by Sam Hocevar. See http://www.wtfpl.net/ for more details. 6 | */ 7 | package net.bridgesapis.bungeebridge.core.players; 8 | 9 | import com.google.gson.JsonArray; 10 | import com.google.gson.JsonObject; 11 | import com.google.gson.JsonParser; 12 | 13 | import java.io.IOException; 14 | import java.net.URL; 15 | import java.net.URLConnection; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.Scanner; 19 | import java.util.UUID; 20 | 21 | class NameFetcher { 22 | private static JsonParser parser = new JsonParser(); 23 | 24 | public static List nameHistoryFromUuid(UUID uuid) { 25 | URLConnection connection; 26 | try { 27 | connection = new URL("https://api.mojang.com/user/profiles/" 28 | + uuid.toString().replace("-", "").toLowerCase() + "/players" 29 | ).openConnection(); 30 | String text = new Scanner(connection.getInputStream()).useDelimiter("\\Z").next(); 31 | JsonArray list = (JsonArray) parser.parse(text); 32 | List names = new ArrayList<>(); 33 | for (int i = 0; i < list.size(); i++) { 34 | names.add(((JsonObject) list.get(i)).get("name").getAsString()); 35 | } 36 | return names; 37 | } catch (IOException e) { 38 | e.printStackTrace(); 39 | } 40 | return null; 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/players/PlayerDataManager.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.core.players; 2 | 3 | import net.bridgesapis.bungeebridge.BungeeBridge; 4 | 5 | import java.util.UUID; 6 | import java.util.concurrent.ConcurrentHashMap; 7 | 8 | /** 9 | * This file is a part of the SamaGames project 10 | * This code is absolutely confidential. 11 | * Created by zyuiop 12 | * (C) Copyright Elydra Network 2015 13 | * All rights reserved. 14 | */ 15 | public class PlayerDataManager { 16 | 17 | protected ConcurrentHashMap cachedData = new ConcurrentHashMap<>(); 18 | private final BungeeBridge bungeeBridge; 19 | 20 | public PlayerDataManager(BungeeBridge bungeeBridge) { 21 | this.bungeeBridge = bungeeBridge; 22 | } 23 | 24 | 25 | public PlayerData getPlayerData(UUID player) { 26 | return getPlayerData(player, false); 27 | } 28 | 29 | public PlayerData getPlayerData(UUID player, boolean forceRefresh) { 30 | if (!cachedData.containsKey(player)) { 31 | PlayerData data = new PlayerData(player, bungeeBridge); 32 | cachedData.put(player, data); 33 | return data; 34 | } 35 | 36 | PlayerData data = cachedData.get(player); 37 | 38 | if (forceRefresh) { 39 | data.updateData(); 40 | return data; 41 | } 42 | 43 | data.refreshIfNeeded(); 44 | return data; 45 | } 46 | 47 | public void update(UUID player) { 48 | if (!cachedData.containsKey(player)) { 49 | PlayerData data = new PlayerData(player, bungeeBridge); 50 | cachedData.put(player, data); 51 | return; 52 | } 53 | 54 | PlayerData data = cachedData.get(player); 55 | data.updateData(); 56 | } 57 | 58 | public void unload(UUID player) { 59 | cachedData.remove(player); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/core/proxies/Subscriber.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.core.proxies; 2 | 3 | import net.bridgesapis.bungeebridge.BungeeBridge; 4 | import net.md_5.bungee.api.ProxyServer; 5 | import net.md_5.bungee.api.config.ServerInfo; 6 | import net.md_5.bungee.api.connection.ProxiedPlayer; 7 | import redis.clients.jedis.JedisPubSub; 8 | 9 | import java.util.UUID; 10 | 11 | public class Subscriber extends JedisPubSub { 12 | 13 | private final NetworkBridge bridge; 14 | 15 | public Subscriber(NetworkBridge bridge) { 16 | this.bridge = bridge; 17 | } 18 | 19 | @Override 20 | public void onMessage(String channel, String message) { 21 | String[] content = message.split(" "); 22 | if (content[0].equalsIgnoreCase("login")) { 23 | if (content.length < 3) 24 | return; 25 | 26 | UUID id = UUID.fromString(content[1]); 27 | String name = content[2]; 28 | } else if (content[0].equalsIgnoreCase("logout")) { 29 | if (content.length < 3) 30 | return; 31 | 32 | UUID id = UUID.fromString(content[1]); 33 | String name = content[2]; 34 | } else if (content[0].equalsIgnoreCase("move")) { 35 | if (content.length < 3) 36 | return; 37 | 38 | UUID id = UUID.fromString(content[1]); 39 | String to = content[2]; 40 | ProxiedPlayer player = ProxyServer.getInstance().getPlayer(id); 41 | if (player != null) { 42 | ServerInfo info = ProxyServer.getInstance().getServerInfo(to); 43 | if (info != null) { 44 | player.connect(info); 45 | } 46 | } 47 | } else if (content[0].equalsIgnoreCase("heartbeat")) { 48 | if (content.length < 2) 49 | return; 50 | 51 | String proxy = content[1]; 52 | bridge.heartBeet(proxy); 53 | } 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/utils/SettingsManager.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.utils; 2 | 3 | import net.bridgesapis.bungeebridge.BungeeBridge; 4 | 5 | import java.util.HashMap; 6 | import java.util.Map; 7 | import java.util.UUID; 8 | 9 | public class SettingsManager { 10 | 11 | public static Map getSettings(UUID player) { 12 | Map data = BungeeBridge.getInstance().getPlayerDataManager().getPlayerData(player).getValues(); 13 | HashMap settings = new HashMap<>(); 14 | data.entrySet().stream().filter(line -> line.getKey().startsWith("settings.")).forEach(line -> { 15 | String setting = line.getKey().split(".")[0]; 16 | settings.put(setting, line.getValue()); 17 | }); 18 | 19 | return settings; 20 | } 21 | 22 | public static String getSetting(UUID player, String setting) { 23 | return BungeeBridge.getInstance().getPlayerDataManager().getPlayerData(player).get("settings." + setting); 24 | } 25 | 26 | public static String getSetting(UUID player, String setting, String def) { 27 | String val = getSetting(player, setting); 28 | return (val == null) ? def : val; 29 | } 30 | 31 | public static boolean isEnabled(UUID player, String setting) { 32 | return BungeeBridge.getInstance().getPlayerDataManager().getPlayerData(player).getBoolean("settings." + setting); 33 | } 34 | 35 | public static boolean isEnabled(UUID player, String setting, boolean val) { 36 | return BungeeBridge.getInstance().getPlayerDataManager().getPlayerData(player).getBoolean("settings." + setting, val); 37 | } 38 | 39 | public static void setSetting(UUID player, String setting, String value) { 40 | BungeeBridge.getInstance().getPlayerDataManager().getPlayerData(player).set("settings." + setting, value); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/commands/CommandDispatch.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.commands; 2 | 3 | import net.bridgesapis.bungeebridge.BungeeBridge; 4 | import net.bridgesapis.bungeebridge.core.database.Publisher; 5 | import net.bridgesapis.bungeebridge.i18n.I18n; 6 | import net.md_5.bungee.api.ChatColor; 7 | import net.md_5.bungee.api.CommandSender; 8 | import net.md_5.bungee.api.chat.ComponentBuilder; 9 | import net.md_5.bungee.api.plugin.Command; 10 | import org.apache.commons.lang3.StringUtils; 11 | 12 | import java.util.Arrays; 13 | 14 | public class CommandDispatch extends Command { 15 | public CommandDispatch() { 16 | super("dispatch", "proxies.dispatch"); 17 | } 18 | 19 | @Override 20 | public void execute(CommandSender commandSender, String[] strings) { 21 | if (strings.length < 3) { 22 | commandSender.sendMessage(new ComponentBuilder("Usage : /dispatch ").color(ChatColor.RED).create()); 23 | } else { 24 | String selector = strings[0]; 25 | String subselector = strings[1]; 26 | String command = StringUtils.join(Arrays.copyOfRange(strings, 2, strings.length), " "); 27 | 28 | switch (selector) { 29 | case "proxies": 30 | BungeeBridge.getInstance().getPublisher().publish(new Publisher.PendingMessage("commands.proxies." + subselector, command)); 31 | commandSender.sendMessage(new ComponentBuilder(I18n.getTranslation("command_sent")).color(ChatColor.GREEN).create()); 32 | break; 33 | case "servers": 34 | BungeeBridge.getInstance().getPublisher().publish(new Publisher.PendingMessage("commands.servers." + subselector, command)); 35 | commandSender.sendMessage(new ComponentBuilder(I18n.getTranslation("command_sent")).color(ChatColor.GREEN).create()); 36 | break; 37 | default: 38 | commandSender.sendMessage(new ComponentBuilder(I18n.getTranslation("commands.dispatch.invalid_selector")).color(ChatColor.RED).create()); 39 | break; 40 | } 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | BungeeBridge 2 | ============ 3 | 4 | BungeeBridge, a reliable cross bungee platform. 5 | 6 | Why BungeeBridge ? 7 | ------------------ 8 | 9 | BungeeBridge is great if you're planning to develop a server with multiple bungeecord proxies linked together. 10 | It allows you to link these proxies through a Redis databases cluster. 11 | 12 | 13 | What is required ? 14 | ------------------ 15 | 16 | BungeeBridge is a BungeeCord plugin, so you need at least one bungeecord server to run it. 17 | You also need at lease two redis DataBases and one redis sentinel. 18 | The sentinel **MUST** use two different masters : 19 | * A storage database, which will keep all the data of your players 20 | * A cache database, which will keep running data 21 | You also have to use our bukkit side bridge, BukkitBridge. This bridge will take care of registering a bukkitserver to the proxy, and a lot of other cool stuff. 22 | This BukkitBridge is designed to be used as an API, so feel free to use it in your plugins. 23 | It includes useful tools to build a network. 24 | 25 | How does it work ? 26 | ------------------ 27 | 28 | Proxies are "linked" through a database. 29 | When a player joins or leaves, a pubsub message is sent and the current amount of players is stored in the database. 30 | Every 15 seconds, each proxy sends a *keepalive* packet to the others. If a proxy doesn't send any keepalive during more than 30 seconds, it's declared as dead and automatically removed from the system. 31 | When a bukkit server with BukkitBridge starts, it'll send a *keepalive* too. The proxies will add the server into the server list. If a server doesn't send any keepalive during more than 2 minutes, it's declared as offline and removed. 32 | 33 | How can I use it ? 34 | ------------------ 35 | 36 | Download binaries : (http://ci.gnomino.eu) 37 | 38 | You can build the plugin : 39 | * Build CrossPermissionsAPI 40 | * Clone this repo 41 | * Run `mvn install` 42 | 43 | **You have to use the -with-dependencies jar file !** 44 | 45 | How can I help ? 46 | ---------------- 47 | 48 | Feel free to fork this repo and do pull requests. There is a TodoList in the CONTRIBUTE.MD file. 49 | -------------------------------------------------------------------------------- /src/main/java/net/bridgesapis/bungeebridge/commands/CommandSetOption.java: -------------------------------------------------------------------------------- 1 | package net.bridgesapis.bungeebridge.commands; 2 | 3 | import net.bridgesapis.bungeebridge.BungeeBridge; 4 | import net.bridgesapis.bungeebridge.core.database.ServerSettings; 5 | import net.bridgesapis.bungeebridge.i18n.I18n; 6 | import net.md_5.bungee.api.ChatColor; 7 | import net.md_5.bungee.api.CommandSender; 8 | import net.md_5.bungee.api.chat.ComponentBuilder; 9 | import org.apache.commons.lang3.StringUtils; 10 | 11 | import java.util.Arrays; 12 | 13 | public class CommandSetOption extends DefaultExecutor { 14 | 15 | private final BungeeBridge plugin; 16 | 17 | public CommandSetOption(BungeeBridge plugin) { 18 | super("setoption", "proxies.setoption", "spo"); 19 | this.plugin = plugin; 20 | } 21 | 22 | @Override 23 | public void execute(CommandSender commandSender, String[] strings) { 24 | if (strings.length < 2) { 25 | commandSender.sendMessage(new ComponentBuilder("Usage : /setoption