use of net.md_5.bungee.api.plugin.Listener in project Geyser by GeyserMC.
the class GeyserBungeeInjector method initializeLocalChannel0.
@Override
@SuppressWarnings("unchecked")
protected void initializeLocalChannel0(GeyserBootstrap bootstrap) throws Exception {
// TODO - allow Geyser to specify its own listener info properties
if (proxy.getConfig().getListeners().size() != 1) {
throw new UnsupportedOperationException("Geyser does not currently support multiple listeners with injection! " + "Please reach out to us on our Discord at https://discord.gg/GeyserMC so we can hear feedback on your setup.");
}
ListenerInfo listenerInfo = proxy.getConfig().getListeners().stream().findFirst().orElseThrow(IllegalStateException::new);
Class<? extends ProxyServer> proxyClass = proxy.getClass();
// Using the specified EventLoop is required, or else an error will be thrown
EventLoopGroup bossGroup;
EventLoopGroup workerGroup;
try {
EventLoopGroup eventLoops = (EventLoopGroup) proxyClass.getField("eventLoops").get(proxy);
// Netty redirects ServerBootstrap#group(EventLoopGroup) to #group(EventLoopGroup, EventLoopGroup) and uses the same event loop for both.
bossGroup = eventLoops;
workerGroup = eventLoops;
bootstrap.getGeyserLogger().debug("BungeeCord event loop style detected.");
} catch (NoSuchFieldException e) {
// Waterfall uses two separate event loops
// https://github.com/PaperMC/Waterfall/blob/fea7ec356dba6c6ac28819ff11be604af6eb484e/BungeeCord-Patches/0022-Use-a-worker-and-a-boss-event-loop-group.patch
bossGroup = (EventLoopGroup) proxyClass.getField("bossEventLoopGroup").get(proxy);
workerGroup = (EventLoopGroup) proxyClass.getField("workerEventLoopGroup").get(proxy);
bootstrap.getGeyserLogger().debug("Waterfall event loop style detected.");
}
// Is currently just AttributeKey.valueOf("ListerInfo") but we might as well copy the value itself.
AttributeKey<ListenerInfo> listener = PipelineUtils.LISTENER;
listenerInfo = new ListenerInfo(listenerInfo.getSocketAddress(), listenerInfo.getMotd(), listenerInfo.getMaxPlayers(), listenerInfo.getTabListSize(), listenerInfo.getServerPriority(), listenerInfo.isForceDefault(), listenerInfo.getForcedHosts(), listenerInfo.getTabListType(), listenerInfo.isSetLocalAddress(), listenerInfo.isPingPassthrough(), listenerInfo.getQueryPort(), listenerInfo.isQueryEnabled(), // If Geyser is expecting HAProxy, so should the Bungee end
bootstrap.getGeyserConfig().getRemote().isUseProxyProtocol());
// The field that stores all listeners in BungeeCord
// As of https://github.com/ViaVersion/ViaVersion/pull/2698 ViaVersion adds a wrapper to this field to
// add its connections
Field listenerField = proxyClass.getDeclaredField("listeners");
listenerField.setAccessible(true);
bungeeChannels = (Set<Channel>) listenerField.get(proxy);
// This method is what initializes the connection in Java Edition, after Netty is all set.
Method initChannel = ChannelInitializer.class.getDeclaredMethod("initChannel", Channel.class);
initChannel.setAccessible(true);
ChannelFuture channelFuture = (new ServerBootstrap().channel(LocalServerChannelWrapper.class).childHandler(new ChannelInitializer<>() {
@Override
protected void initChannel(Channel ch) throws Exception {
if (proxy.getConfig().getServers() == null) {
// Proxy hasn't finished loading all plugins - it loads the config after all plugins
// Probably doesn't need to be translatable?
bootstrap.getGeyserLogger().info("Disconnecting player as Bungee has not finished loading");
ch.close();
return;
}
if (channelInitializer == null) {
// Proxy has finished initializing; we can safely grab this variable without fear of plugins modifying it
// (Older versions of ViaVersion replace this to inject)
channelInitializer = PipelineUtils.SERVER_CHILD;
}
initChannel.invoke(channelInitializer, ch);
}
}).childAttr(listener, listenerInfo).group(bossGroup, workerGroup).localAddress(LocalAddress.ANY)).bind().syncUninterruptibly();
this.localChannel = channelFuture;
this.bungeeChannels.add(this.localChannel.channel());
this.serverSocketAddress = channelFuture.channel().localAddress();
if (!this.eventRegistered) {
// Register reload listener
this.proxy.getPluginManager().registerListener(this.plugin, this);
this.eventRegistered = true;
}
// Only affects Waterfall, but there is no sure way to differentiate between a proxy with this patch and a proxy without this patch
// Patch causing the issue: https://github.com/PaperMC/Waterfall/blob/7e6af4cef64d5d377a6ffd00a534379e6efa94cf/BungeeCord-Patches/0045-Don-t-use-a-bytebuf-for-packet-decoding.patch
// If native compression is enabled, then this line is tripped up if a heap buffer is sent over in such a situation
// as a new direct buffer is not created with that patch (HeapByteBufs throw an UnsupportedOperationException here):
// https://github.com/SpigotMC/BungeeCord/blob/a283aaf724d4c9a815540cd32f3aafaa72df9e05/native/src/main/java/net/md_5/bungee/jni/zlib/NativeZlib.java#L43
// This issue could be mitigated down the line by preventing Bungee from setting compression
LocalSession.createDirectByteBufAllocator();
}
use of net.md_5.bungee.api.plugin.Listener in project BungeeTabListPlus by CodeCrafter47.
the class RedisPlayerManager method updatePlayers.
private void updatePlayers() {
Set<UUID> playersOnline;
try {
playersOnline = RedisBungee.getApi().getPlayersOnline();
} catch (Throwable th) {
if (!redisBungeeAPIError) {
logger.log(Level.WARNING, "Error using RedisBungee API", th);
redisBungeeAPIError = true;
}
return;
}
redisBungeeAPIError = false;
// fetch names for new players
Map<UUID, String> uuidToNameMap = new Object2ObjectOpenHashMap<>();
for (UUID uuid : playersOnline) {
if (!byUUID.containsKey(uuid) && ProxyServer.getInstance().getPlayer(uuid) == null) {
try {
uuidToNameMap.put(uuid, RedisBungee.getApi().getNameFromUuid(uuid));
} catch (Throwable ex) {
logger.log(Level.WARNING, "Error while using RedisBungee API", ex);
}
}
}
redisConnectionSuccessful = true;
try {
mainThread.submit(() -> {
// remove players which have gone offline
for (Iterator<UUID> iterator = byUUID.keySet().iterator(); iterator.hasNext(); ) {
UUID uuid = iterator.next();
if (!playersOnline.contains(uuid) || ProxyServer.getInstance().getPlayer(uuid) != null) {
RedisPlayer redisPlayer = byUUID.get(uuid);
iterator.remove();
listeners.forEach(listener -> listener.onPlayerRemoved(redisPlayer));
}
}
// add new players
for (UUID uuid : uuidToNameMap.keySet()) {
if (!byUUID.containsKey(uuid) && ProxyServer.getInstance().getPlayer(uuid) == null) {
RedisPlayer redisPlayer = new RedisPlayer(uuid, uuidToNameMap.get(uuid));
byUUID.put(uuid, redisPlayer);
listeners.forEach(listener -> listener.onPlayerAdded(redisPlayer));
}
}
}).sync();
} catch (InterruptedException ignored) {
}
}
use of net.md_5.bungee.api.plugin.Listener in project SubServers-2 by ME1312.
the class PacketDownloadPlatformInfo method send.
@Override
public ObjectMap<Integer> send(SubDataClient client) {
ObjectMap<Integer> data = new ObjectMap<Integer>();
if (tracker != null)
data.set(0x0000, tracker);
ObjectMap<String> info = new ObjectMap<String>();
ObjectMap<String> subservers = new ObjectMap<String>();
subservers.set("version", plugin.api.getWrapperVersion().toString());
if (plugin.api.getWrapperBuild() != null)
subservers.set("build", plugin.api.getWrapperBuild().toString());
subservers.set("last-reload", plugin.resetDate);
subservers.set("proxies", plugin.api.getProxies().size());
subservers.set("hosts", plugin.api.getHosts().size());
subservers.set("subservers", plugin.api.getSubServers().size());
info.set("subservers", subservers);
ObjectMap<String> bungee = new ObjectMap<String>();
bungee.set("version", plugin.api.getProxyVersion().toString());
bungee.set("disabled-cmds", plugin.getConfig().getDisabledCommands());
bungee.set("player-limit", plugin.getConfig().getPlayerLimit());
bungee.set("servers", plugin.api.getServers().size());
LinkedList<ObjectMap<String>> listeners = new LinkedList<ObjectMap<String>>();
for (ListenerInfo next : plugin.getConfig().getListeners()) {
ObjectMap<String> listener = new ObjectMap<String>();
listener.set("forced-hosts", next.getForcedHosts());
listener.set("motd", next.getMotd());
listener.set("priorities", next.getServerPriority());
listener.set("player-limit", next.getMaxPlayers());
listeners.add(listener);
}
bungee.set("listeners", listeners);
info.set("bungee", bungee);
ObjectMap<String> minecraft = new ObjectMap<String>();
LinkedList<String> mcversions = new LinkedList<String>();
for (Version version : plugin.api.getGameVersion()) mcversions.add(version.toString());
minecraft.set("version", mcversions);
minecraft.set("players", plugin.api.getRemotePlayers().size());
info.set("minecraft", minecraft);
ObjectMap<String> system = new ObjectMap<String>();
ObjectMap<String> os = new ObjectMap<String>();
os.set("name", System.getProperty("os.name"));
os.set("version", System.getProperty("os.version"));
system.set("os", os);
ObjectMap<String> java = new ObjectMap<String>();
java.set("version", System.getProperty("java.version"));
system.set("java", java);
info.set("system", system);
data.set(0x0001, info);
return data;
}
use of net.md_5.bungee.api.plugin.Listener in project BungeeCord by SpigotMC.
the class Configuration method load.
public void load() {
ConfigurationAdapter adapter = ProxyServer.getInstance().getConfigurationAdapter();
adapter.load();
File fav = new File("server-icon.png");
if (fav.exists()) {
try {
favicon = Favicon.create(ImageIO.read(fav));
} catch (IOException | IllegalArgumentException ex) {
ProxyServer.getInstance().getLogger().log(Level.WARNING, "Could not load server icon", ex);
}
}
listeners = adapter.getListeners();
timeout = adapter.getInt("timeout", timeout);
uuid = adapter.getString("stats", uuid);
onlineMode = adapter.getBoolean("online_mode", onlineMode);
logCommands = adapter.getBoolean("log_commands", logCommands);
logPings = adapter.getBoolean("log_pings", logPings);
remotePingCache = adapter.getInt("remote_ping_cache", remotePingCache);
playerLimit = adapter.getInt("player_limit", playerLimit);
serverConnectTimeout = adapter.getInt("server_connect_timeout", serverConnectTimeout);
remotePingTimeout = adapter.getInt("remote_ping_timeout", remotePingTimeout);
throttle = adapter.getInt("connection_throttle", throttle);
throttleLimit = adapter.getInt("connection_throttle_limit", throttleLimit);
ipForward = adapter.getBoolean("ip_forward", ipForward);
compressionThreshold = adapter.getInt("network_compression_threshold", compressionThreshold);
preventProxyConnections = adapter.getBoolean("prevent_proxy_connections", preventProxyConnections);
forgeSupport = adapter.getBoolean("forge_support", forgeSupport);
disabledCommands = new CaseInsensitiveSet((Collection<String>) adapter.getList("disabled_commands", Arrays.asList("disabledcommandhere")));
Preconditions.checkArgument(listeners != null && !listeners.isEmpty(), "No listeners defined.");
Map<String, ServerInfo> newServers = adapter.getServers();
Preconditions.checkArgument(newServers != null && !newServers.isEmpty(), "No servers defined");
if (servers == null) {
servers = new CaseInsensitiveMap<>(newServers);
} else {
for (ServerInfo oldServer : servers.values()) {
// Don't allow servers to be removed
Preconditions.checkArgument(newServers.containsKey(oldServer.getName()), "Server %s removed on reload!", oldServer.getName());
}
// Add new servers
for (Map.Entry<String, ServerInfo> newServer : newServers.entrySet()) {
if (!servers.containsValue(newServer.getValue())) {
servers.put(newServer.getKey(), newServer.getValue());
}
}
}
for (ListenerInfo listener : listeners) {
for (int i = 0; i < listener.getServerPriority().size(); i++) {
String server = listener.getServerPriority().get(i);
Preconditions.checkArgument(servers.containsKey(server), "Server %s (priority %s) is not defined", server, i);
}
for (String server : listener.getForcedHosts().values()) {
if (!servers.containsKey(server)) {
ProxyServer.getInstance().getLogger().log(Level.WARNING, "Forced host server {0} is not defined", server);
}
}
}
}
use of net.md_5.bungee.api.plugin.Listener in project BungeeCord by SpigotMC.
the class UserConnection method connect.
@Override
public void connect(final ServerConnectRequest request) {
Preconditions.checkNotNull(request, "request");
final Callback<ServerConnectRequest.Result> callback = request.getCallback();
ServerConnectEvent event = new ServerConnectEvent(this, request.getTarget(), request.getReason(), request);
if (bungee.getPluginManager().callEvent(event).isCancelled()) {
if (callback != null) {
callback.done(ServerConnectRequest.Result.EVENT_CANCEL, null);
}
if (getServer() == null && !ch.isClosing()) {
throw new IllegalStateException("Cancelled ServerConnectEvent with no server or disconnect.");
}
return;
}
// Update in case the event changed target
final BungeeServerInfo target = (BungeeServerInfo) event.getTarget();
if (getServer() != null && Objects.equals(getServer().getInfo(), target)) {
if (callback != null) {
callback.done(ServerConnectRequest.Result.ALREADY_CONNECTED, null);
}
sendMessage(bungee.getTranslation("already_connected"));
return;
}
if (pendingConnects.contains(target)) {
if (callback != null) {
callback.done(ServerConnectRequest.Result.ALREADY_CONNECTING, null);
}
sendMessage(bungee.getTranslation("already_connecting"));
return;
}
pendingConnects.add(target);
ChannelInitializer initializer = new ChannelInitializer() {
@Override
protected void initChannel(Channel ch) throws Exception {
PipelineUtils.BASE.initChannel(ch);
ch.pipeline().addAfter(PipelineUtils.FRAME_DECODER, PipelineUtils.PACKET_DECODER, new MinecraftDecoder(Protocol.HANDSHAKE, false, getPendingConnection().getVersion()));
ch.pipeline().addAfter(PipelineUtils.FRAME_PREPENDER, PipelineUtils.PACKET_ENCODER, new MinecraftEncoder(Protocol.HANDSHAKE, false, getPendingConnection().getVersion()));
ch.pipeline().get(HandlerBoss.class).setHandler(new ServerConnector(bungee, UserConnection.this, target));
}
};
ChannelFutureListener listener = new ChannelFutureListener() {
@Override
@SuppressWarnings("ThrowableResultIgnored")
public void operationComplete(ChannelFuture future) throws Exception {
if (callback != null) {
callback.done((future.isSuccess()) ? ServerConnectRequest.Result.SUCCESS : ServerConnectRequest.Result.FAIL, future.cause());
}
if (!future.isSuccess()) {
future.channel().close();
pendingConnects.remove(target);
ServerInfo def = updateAndGetNextServer(target);
if (request.isRetry() && def != null && (getServer() == null || def != getServer().getInfo())) {
sendMessage(bungee.getTranslation("fallback_lobby"));
connect(def, null, true, ServerConnectEvent.Reason.LOBBY_FALLBACK);
} else if (dimensionChange) {
disconnect(bungee.getTranslation("fallback_kick", connectionFailMessage(future.cause())));
} else {
sendMessage(bungee.getTranslation("fallback_kick", connectionFailMessage(future.cause())));
}
}
}
};
Bootstrap b = new Bootstrap().channel(PipelineUtils.getChannel(target.getAddress())).group(ch.getHandle().eventLoop()).handler(initializer).option(ChannelOption.CONNECT_TIMEOUT_MILLIS, request.getConnectTimeout()).remoteAddress(target.getAddress());
// Windows is bugged, multi homed users will just have to live with random connecting IPs
if (getPendingConnection().getListener().isSetLocalAddress() && !PlatformDependent.isWindows() && getPendingConnection().getListener().getSocketAddress() instanceof InetSocketAddress) {
b.localAddress(getPendingConnection().getListener().getHost().getHostString(), 0);
}
b.connect().addListener(listener);
}
Aggregations