2
0
mirror of https://github.com/proxiodev/RedisBungee.git synced 2026-04-09 00:20:26 +00:00

redo module system

This commit is contained in:
2024-05-12 14:59:50 +04:00
parent e8514b3e8b
commit 765e6fe122
95 changed files with 388 additions and 70 deletions

View File

@@ -0,0 +1,82 @@
plugins {
java
id("com.github.johnrengelman.shadow") version "8.1.1"
id("xyz.jpenilla.run-waterfall") version "2.0.0"
}
dependencies {
implementation(project(":RedisBungee-Bungee"))
compileOnly(libs.platform.bungeecord) {
exclude("com.google.guava", "guava")
exclude("com.google.code.gson", "gson")
exclude("net.kyori","adventure-api")
}
implementation(libs.adventure.platforms.bungeecord)
implementation(libs.adventure.gson)
implementation(libs.acf.bungeecord)
implementation(project(":RedisBungee-Commands"))
}
description = "RedisBungee Bungeecord implementation"
java {
withJavadocJar()
withSourcesJar()
}
tasks {
withType<Javadoc> {
dependsOn(project(":RedisBungee-API").getTasksByName("javadoc", false))
val options = options as StandardJavadocDocletOptions
options.use()
options.isDocFilesSubDirs = true
options.links(
"https://ci.md-5.net/job/BungeeCord/ws/api/target/apidocs/", // bungeecord api
)
val apiDocs = File(rootProject.projectDir, "RedisBungee-API/build/docs/javadoc")
options.linksOffline("https://ci.limework.net/RedisBungee/RedisBungee-API/build/docs/javadoc", apiDocs.path)
}
runWaterfall {
waterfallVersion("1.20")
environment["REDISBUNGEE_PROXY_ID"] = "bungeecord-1"
environment["REDISBUNGEE_NETWORK_ID"] = "dev"
}
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(17)
}
javadoc {
options.encoding = Charsets.UTF_8.name()
}
processResources {
filteringCharset = Charsets.UTF_8.name()
filesMatching("plugin.yml") {
filter {
it.replace("*{redisbungee.version}*", "$version", false)
}
}
}
shadowJar {
relocate("redis.clients.jedis", "com.imaginarycode.minecraft.redisbungee.internal.jedis")
relocate("redis.clients.util", "com.imaginarycode.minecraft.redisbungee.internal.jedisutil")
relocate("org.apache.commons.pool", "com.imaginarycode.minecraft.redisbungee.internal.commonspool")
relocate("com.squareup.okhttp", "com.imaginarycode.minecraft.redisbungee.internal.okhttp")
relocate("okio", "com.imaginarycode.minecraft.redisbungee.internal.okio")
relocate("org.json", "com.imaginarycode.minecraft.redisbungee.internal.json")
// configurate shade
relocate("ninja.leaping.configurate", "com.imaginarycode.minecraft.redisbungee.internal.configurate")
relocate("org.yaml", "com.imaginarycode.minecraft.redisbungee.internal.yml")
relocate("com.google.common", "com.imaginarycode.minecraft.redisbungee.internal.com.google.common")
relocate("com.google.errorprone", "com.imaginarycode.minecraft.redisbungee.internal.com.google.errorprone")
relocate("com.google.gson", "com.imaginarycode.minecraft.redisbungee.internal.com.google.gson")
relocate("com.google.j2objc", "com.imaginarycode.minecraft.redisbungee.internal.com.google.j2objc")
relocate("com.google.thirdparty", "com.imaginarycode.minecraft.redisbungee.internal.com.google.thirdparty")
relocate("com.github.benmanes.caffeine", "com.imaginarycode.minecraft.redisbungee.internal.caffeine")
// acf shade
relocate("co.aikar.commands", "com.imaginarycode.minecraft.redisbungee.internal.acf.commands")
}
}

View File

@@ -0,0 +1,51 @@
plugins {
`java-library`
`maven-publish`
}
dependencies {
api(project(":RedisBungee-API"))
compileOnly(libs.platform.bungeecord) {
exclude("com.google.guava", "guava")
exclude("com.google.code.gson", "gson")
exclude("net.kyori","adventure-api")
}
}
description = "RedisBungee Bungeecord API"
java {
withJavadocJar()
withSourcesJar()
}
tasks {
withType<Javadoc> {
dependsOn(project(":RedisBungee-API").getTasksByName("javadoc", false))
val path = project(":RedisBungee-API").path
val options = options as StandardJavadocDocletOptions
options.use()
options.isDocFilesSubDirs = true
options.links(
"https://ci.md-5.net/job/BungeeCord/ws/api/target/apidocs/", // bungeecord api
)
val apiDocs = File(rootProject.projectDir, "$path/build/docs/javadoc")
options.linksOffline("https://ci.limework.net/ValioBungee/api/build/docs/javadoc", apiDocs.path)
}
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(17)
}
javadoc {
options.encoding = Charsets.UTF_8.name()
}
}
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID;
/**
* This platform class exposes some internal RedisBungee functions. You obtain an instance of this object by invoking {@link RedisBungeeAPI#getRedisBungeeApi()}
* or somehow you got the Plugin instance by you can call the api using {@link RedisBungeePlugin#getAbstractRedisBungeeApi()}.
*
* @author tuxed
* @since 0.2.3 | updated 0.8.0
*/
public class RedisBungeeAPI extends AbstractRedisBungeeAPI {
private static RedisBungeeAPI redisBungeeApi;
public RedisBungeeAPI(RedisBungeePlugin<?> plugin) {
super(plugin);
if (redisBungeeApi == null) {
redisBungeeApi = this;
}
}
/**
* Get the server where the specified player is playing. This function also deals with the case of local players
* as well, and will return local information on them.
*
* @param player a player uuid
* @return {@link ServerInfo} Can be null if proxy can't find it.
* @see #getServerNameFor(UUID)
*/
@Nullable
public final ServerInfo getServerFor(@NonNull UUID player) {
String serverName = this.getServerNameFor(player);
if (serverName == null) return null;
return ((Plugin) this.plugin).getProxy().getServerInfo(serverName);
}
/**
* Api instance
*
* @return the API instance.
* @since 0.6.5
*/
public static RedisBungeeAPI getRedisBungeeApi() {
return redisBungeeApi;
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.events;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerChangedServerNetworkEvent;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* This event is sent when a player connects to a new server. RedisBungee sends the event only when
* the proxy the player has been connected to is different than the local proxy.
* <p>
* This event corresponds to {@link net.md_5.bungee.api.event.ServerConnectedEvent}, and is fired
* asynchronously.
*
* @since 0.3.4
*/
public class PlayerChangedServerNetworkEvent extends Event implements IPlayerChangedServerNetworkEvent {
private final UUID uuid;
private final String previousServer;
private final String server;
public PlayerChangedServerNetworkEvent(UUID uuid, String previousServer, String server) {
this.uuid = uuid;
this.previousServer = previousServer;
this.server = server;
}
@Override
public UUID getUuid() {
return uuid;
}
@Override
public String getServer() {
return server;
}
@Override
public String getPreviousServer() {
return previousServer;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.events;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* This event is sent when a player joins the network. RedisBungee sends the event only when
* the proxy the player has been connected to is different than the local proxy.
* <p>
* This event corresponds to {@link net.md_5.bungee.api.event.PostLoginEvent}, and is fired
* asynchronously.
*
* @since 0.3.4
*/
public class PlayerJoinedNetworkEvent extends Event implements IPlayerJoinedNetworkEvent {
private final UUID uuid;
public PlayerJoinedNetworkEvent(UUID uuid) {
this.uuid = uuid;
}
@Override
public UUID getUuid() {
return uuid;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.events;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* This event is sent when a player disconnects. RedisBungee sends the event only when
* the proxy the player has been connected to is different than the local proxy.
* <p>
* This event corresponds to {@link net.md_5.bungee.api.event.PlayerDisconnectEvent}, and is fired
* asynchronously.
*
* @since 0.3.4
*/
public class PlayerLeftNetworkEvent extends Event implements IPlayerLeftNetworkEvent {
private final UUID uuid;
public PlayerLeftNetworkEvent(UUID uuid) {
this.uuid = uuid;
}
@Override
public UUID getUuid() {
return uuid;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.events;
import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent;
import net.md_5.bungee.api.plugin.Event;
/**
* This event is posted when a PubSub message is received.
* <p>
* <strong>Warning</strong>: This event is fired in a separate thread!
*
* @since 0.2.6
*/
public class PubSubMessageEvent extends Event implements IPubSubMessageEvent {
private final String channel;
private final String message;
public PubSubMessageEvent(String channel, String message) {
this.channel = channel;
this.message = message;
}
@Override
public String getChannel() {
return channel;
}
@Override
public String getMessage() {
return message;
}
}

View File

@@ -0,0 +1,17 @@
package com.imaginarycode.minecraft.redisbungee;
import co.aikar.commands.BungeeCommandIssuer;
import co.aikar.commands.CommandIssuer;
import com.imaginarycode.minecraft.redisbungee.commands.utils.CommandPlatformHelper;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
public class BungeeCommandPlatformHelper extends CommandPlatformHelper {
@Override
public void sendMessage(CommandIssuer issuer, Component component) {
BungeeCommandIssuer bIssuer = (BungeeCommandIssuer) issuer;
bIssuer.getIssuer().sendMessage(BungeeComponentSerializer.get().serialize(component));
}
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee;
import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.event.ServerConnectedEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.event.EventHandler;
import java.util.concurrent.TimeUnit;
public class BungeePlayerDataManager extends PlayerDataManager<ProxiedPlayer, PostLoginEvent, PlayerDisconnectEvent, PubSubMessageEvent, PlayerChangedServerNetworkEvent, PlayerLeftNetworkEvent, ServerConnectedEvent> implements Listener {
public BungeePlayerDataManager(RedisBungeePlugin<ProxiedPlayer> plugin) {
super(plugin);
}
@Override
@EventHandler
public void onPlayerChangedServerNetworkEvent(PlayerChangedServerNetworkEvent event) {
super.handleNetworkPlayerServerChange(event);
}
@Override
@EventHandler
public void onNetworkPlayerQuit(PlayerLeftNetworkEvent event) {
super.handleNetworkPlayerQuit(event);
}
@Override
@EventHandler
public void onPubSubMessageEvent(PubSubMessageEvent event) {
super.handlePubSubMessageEvent(event);
}
@Override
@EventHandler
public void onServerConnectedEvent(ServerConnectedEvent event) {
final String currentServer = event.getServer().getInfo().getName();
final String oldServer = event.getPlayer().getServer() == null ? null : event.getPlayer().getServer().getInfo().getName();
super.playerChangedServer(event.getPlayer().getUniqueId(), oldServer, currentServer);
}
@EventHandler
public void onLoginEvent(LoginEvent event) {
event.registerIntent((Plugin) plugin);
// check if online
if (getLastOnline(event.getConnection().getUniqueId()) == 0) {
if (plugin.configuration().kickWhenOnline()) {
kickPlayer(event.getConnection().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation());
// wait 3 seconds before releasing the event
plugin.executeAsyncAfter(() -> event.completeIntent((Plugin) plugin), TimeUnit.SECONDS, 3);
} else {
event.setCancelled(true);
event.setCancelReason(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().alreadyLoggedIn()));
event.completeIntent((Plugin) plugin);
}
} else {
event.completeIntent((Plugin) plugin);
}
}
@Override
@EventHandler
public void onLoginEvent(PostLoginEvent event) {
super.addPlayer(event.getPlayer().getUniqueId(), event.getPlayer().getName(), event.getPlayer().getAddress().getAddress());
}
@Override
@EventHandler
public void onDisconnectEvent(PlayerDisconnectEvent event) {
super.removePlayer(event.getPlayer().getUniqueId());
}
}

View File

@@ -0,0 +1,373 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee;
import co.aikar.commands.BungeeCommandManager;
import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager;
import com.imaginarycode.minecraft.redisbungee.api.ProxyDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.config.LangConfiguration;
import com.imaginarycode.minecraft.redisbungee.api.config.loaders.ConfigLoader;
import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration;
import com.imaginarycode.minecraft.redisbungee.api.config.loaders.LangConfigLoader;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerChangedServerNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner;
import com.imaginarycode.minecraft.redisbungee.api.util.InitialUtils;
import com.imaginarycode.minecraft.redisbungee.api.util.uuid.NameFetcher;
import com.imaginarycode.minecraft.redisbungee.api.util.uuid.UUIDFetcher;
import com.imaginarycode.minecraft.redisbungee.api.util.uuid.UUIDTranslator;
import com.imaginarycode.minecraft.redisbungee.commands.CommandLoader;
import com.imaginarycode.minecraft.redisbungee.commands.utils.CommandPlatformHelper;
import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import com.squareup.okhttp.Dispatcher;
import com.squareup.okhttp.OkHttpClient;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Event;
import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.api.scheduler.ScheduledTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.JedisPool;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.sql.Date;
import java.time.Instant;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.*;
import java.util.logging.Level;
public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlayer>, ConfigLoader, LangConfigLoader {
private static RedisBungeeAPI apiStatic;
private AbstractRedisBungeeAPI api;
private RedisBungeeMode redisBungeeMode;
private ProxyDataManager proxyDataManager;
private BungeePlayerDataManager playerDataManager;
private ScheduledTask heartbeatTask;
private ScheduledTask cleanupTask;
private Summoner<?> summoner;
private UUIDTranslator uuidTranslator;
private RedisBungeeConfiguration configuration;
private LangConfiguration langConfiguration;
private OkHttpClient httpClient;
private BungeeCommandManager commandManager;
private final Logger logger = LoggerFactory.getLogger("RedisBungee");
@Override
public RedisBungeeConfiguration configuration() {
return this.configuration;
}
@Override
public LangConfiguration langConfiguration() {
return this.langConfiguration;
}
@Override
public AbstractRedisBungeeAPI getAbstractRedisBungeeApi() {
return this.api;
}
@Override
public ProxyDataManager proxyDataManager() {
return this.proxyDataManager;
}
@Override
public PlayerDataManager<ProxiedPlayer, ?, ?, ?, ?, ?, ?> playerDataManager() {
return this.playerDataManager;
}
@Override
public UUIDTranslator getUuidTranslator() {
return this.uuidTranslator;
}
@Override
public void fireEvent(Object event) {
this.getProxy().getPluginManager().callEvent((Event) event);
}
@Override
public boolean isOnlineMode() {
return this.getProxy().getConfig().isOnlineMode();
}
@Override
public void logInfo(String msg) {
this.logger.info(msg);
}
@Override
public void logInfo(String format, Object... object) {
this.logger.info(format, object);
}
@Override
public void logWarn(String msg) {
this.logger.warn(msg);
}
@Override
public void logWarn(String format, Object... object) {
this.logger.warn(format, object);
}
@Override
public void logFatal(String msg) {
this.logger.error(msg);
}
@Override
public void logFatal(String format, Throwable throwable) {
this.logger.error(format, throwable);
}
@Override
public ProxiedPlayer getPlayer(UUID uuid) {
return this.getProxy().getPlayer(uuid);
}
@Override
public ProxiedPlayer getPlayer(String name) {
return this.getProxy().getPlayer(name);
}
@Override
public UUID getPlayerUUID(String player) {
return this.getProxy().getPlayer(player).getUniqueId();
}
@Override
public String getPlayerName(UUID player) {
return this.getProxy().getPlayer(player).getName();
}
@Override
public boolean handlePlatformKick(UUID uuid, Component message) {
ProxiedPlayer player = getPlayer(uuid);
if (player == null) return false;
if (!player.isConnected()) return false;
player.disconnect(BungeeComponentSerializer.get().serialize(message));
return true;
}
@Override
public String getPlayerServerName(ProxiedPlayer player) {
return player.getServer().getInfo().getName();
}
@Override
public boolean isPlayerOnAServer(ProxiedPlayer player) {
return player.getServer() != null;
}
@Override
public InetAddress getPlayerIp(ProxiedPlayer player) {
return player.getAddress().getAddress();
}
@Override
public void initialize() {
logInfo("Initializing RedisBungee.....");
logInfo("Version: {}", Constants.VERSION);
ThreadFactory factory = ((ThreadPoolExecutor) getExecutorService()).getThreadFactory();
ScheduledExecutorService service = Executors.newScheduledThreadPool(24, factory);
try {
Field field = Plugin.class.getDeclaredField("service");
field.setAccessible(true);
ExecutorService builtinService = (ExecutorService) field.get(this);
field.set(this, service);
builtinService.shutdownNow();
} catch (IllegalAccessException | NoSuchFieldException e) {
getLogger().log(Level.WARNING, "Can't replace BungeeCord thread pool with our own");
getLogger().log(Level.WARNING, "skipping replacement.....");
}
try {
loadConfig(this, getDataFolder().toPath());
loadLangConfig(this, getDataFolder().toPath());
} catch (IOException e) {
throw new RuntimeException("Unable to load/save config", e);
}
// init the proxy data manager
this.proxyDataManager = new ProxyDataManager(this) {
@Override
public Set<UUID> getLocalOnlineUUIDs() {
HashSet<UUID> uuids = new HashSet<>();
ProxyServer.getInstance().getPlayers().forEach((proxiedPlayer) -> uuids.add(proxiedPlayer.getUniqueId()));
return uuids;
}
@Override
protected void handlePlatformCommandExecution(String command) {
logInfo("Dispatching {}", command);
ProxyServer.getInstance().getPluginManager().dispatchCommand(RedisBungeeCommandSender.getSingleton(), command);
}
};
this.playerDataManager = new BungeePlayerDataManager(this);
getProxy().getPluginManager().registerListener(this, this.playerDataManager);
getProxy().getPluginManager().registerListener(this, new RedisBungeeListener(this));
// start listening
getProxy().getScheduler().runAsync(this, proxyDataManager);
// heartbeat
this.heartbeatTask = getProxy().getScheduler().schedule(this, () -> this.proxyDataManager.publishHeartbeat(), 0, 1, TimeUnit.SECONDS);
// cleanup
this.cleanupTask = getProxy().getScheduler().schedule(this, () -> this.proxyDataManager.correctionTask(), 0, 60, TimeUnit.SECONDS);
// init the http lib
httpClient = new OkHttpClient();
Dispatcher dispatcher = new Dispatcher(getExecutorService());
httpClient.setDispatcher(dispatcher);
NameFetcher.setHttpClient(httpClient);
UUIDFetcher.setHttpClient(httpClient);
InitialUtils.checkRedisVersion(this);
uuidTranslator = new UUIDTranslator(this);
// register plugin messages channel.
getProxy().registerChannel("legacy:redisbungee");
getProxy().registerChannel("RedisBungee");
// init the api
this.api = new RedisBungeeAPI(this);
apiStatic = (RedisBungeeAPI) this.api;
// commands
CommandPlatformHelper.init(new BungeeCommandPlatformHelper());
this.commandManager = new BungeeCommandManager(this);
CommandLoader.initCommands(this.commandManager, this);
logInfo("RedisBungee initialized successfully ");
}
@Override
public void stop() {
logInfo("Turning off redis connections.....");
getProxy().getPluginManager().unregisterListeners(this);
if (this.cleanupTask != null) {
this.cleanupTask.cancel();
}
if (heartbeatTask != null) {
heartbeatTask.cancel();
}
try {
this.proxyDataManager.close();
} catch (Exception e) {
throw new RuntimeException(e);
}
try {
this.summoner.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
if (this.commandManager != null) {
this.commandManager.unregisterCommands();
}
logInfo("RedisBungee shutdown successfully");
}
@Override
public Summoner<?> getSummoner() {
return this.summoner;
}
@Override
public RedisBungeeMode getRedisBungeeMode() {
return this.redisBungeeMode;
}
@Override
public void executeAsync(Runnable runnable) {
this.getProxy().getScheduler().runAsync(this, runnable);
}
@Override
public void executeAsyncAfter(Runnable runnable, TimeUnit timeUnit, int time) {
this.getProxy().getScheduler().schedule(this, runnable, time, timeUnit);
}
@Override
public void onEnable() {
initialize();
}
@Override
public void onDisable() {
stop();
}
@Override
public IPlayerChangedServerNetworkEvent createPlayerChangedServerNetworkEvent(UUID uuid, String previousServer, String server) {
return new PlayerChangedServerNetworkEvent(uuid, previousServer, server);
}
@Override
public IPlayerJoinedNetworkEvent createPlayerJoinedNetworkEvent(UUID uuid) {
return new PlayerJoinedNetworkEvent(uuid);
}
@Override
public IPlayerLeftNetworkEvent createPlayerLeftNetworkEvent(UUID uuid) {
return new PlayerLeftNetworkEvent(uuid);
}
@Override
public IPubSubMessageEvent createPubSubEvent(String channel, String message) {
return new PubSubMessageEvent(channel, message);
}
@Override
public void onConfigLoad(RedisBungeeConfiguration configuration, Summoner<?> summoner, RedisBungeeMode mode) {
this.configuration = configuration;
this.redisBungeeMode = mode;
this.summoner = summoner;
}
/**
* This returns an instance of {@link RedisBungeeAPI}
*
* @return the {@link AbstractRedisBungeeAPI} object instance.
* @deprecated Please use {@link RedisBungeeAPI#getRedisBungeeApi()} this class intended to for old plugins that no longer updated.
*/
@Deprecated
public static RedisBungeeAPI getApi() {
return apiStatic;
}
@Deprecated
public JedisPool getPool() {
return api.getJedisPool();
}
@Override
public void onLangConfigLoad(LangConfiguration langConfiguration) {
this.langConfiguration = langConfiguration;
}
}

View File

@@ -0,0 +1,63 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import net.md_5.bungee.api.config.ServerInfo;
import net.md_5.bungee.api.plugin.Plugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import java.util.UUID;
/**
* This platform class exposes some internal RedisBungee functions. You obtain an instance of this object by invoking {@link RedisBungeeAPI#getRedisBungeeApi()}
* or somehow you got the Plugin instance by you can call the api using {@link RedisBungeePlugin#getAbstractRedisBungeeApi()}.
*
* @author tuxed
* @since 0.2.3 | updated 0.8.0
*/
public class RedisBungeeAPI extends AbstractRedisBungeeAPI {
private static RedisBungeeAPI redisBungeeApi;
public RedisBungeeAPI(RedisBungeePlugin<?> plugin) {
super(plugin);
if (redisBungeeApi == null) {
redisBungeeApi = this;
}
}
/**
* Get the server where the specified player is playing. This function also deals with the case of local players
* as well, and will return local information on them.
*
* @param player a player uuid
* @return {@link ServerInfo} Can be null if proxy can't find it.
* @see #getServerNameFor(UUID)
*/
@Nullable
public final ServerInfo getServerFor(@NonNull UUID player) {
String serverName = this.getServerNameFor(player);
if (serverName == null) return null;
return ((Plugin) this.plugin).getProxy().getServerInfo(serverName);
}
/**
* Api instance
*
* @return the API instance.
* @since 0.6.5
*/
public static RedisBungeeAPI getRedisBungeeApi() {
return redisBungeeApi;
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.BaseComponent;
import java.util.Collection;
import java.util.Collections;
public class RedisBungeeCommandSender implements CommandSender {
private static final RedisBungeeCommandSender singleton;
static {
singleton = new RedisBungeeCommandSender();
}
public static RedisBungeeCommandSender getSingleton() {
return singleton;
}
@Override
public String getName() {
return "RedisBungee";
}
@Override
public void sendMessage(String s) {
}
@Override
public void sendMessages(String... strings) {
}
@Override
public void sendMessage(BaseComponent... baseComponents) {
}
@Override
public void sendMessage(BaseComponent baseComponent) {
}
@Override
public Collection<String> getGroups() {
return null;
}
@Override
public void addGroups(String... strings) {
}
@Override
public void removeGroups(String... strings) {
}
@Override
public boolean hasPermission(String s) {
return true;
}
@Override
public void setPermission(String s, boolean b) {
}
@Override
public Collection<String> getPermissions() {
return Collections.emptySet();
}
}

View File

@@ -0,0 +1,168 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee;
import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.AbstractReconnectHandler;
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.api.connection.Server;
import net.md_5.bungee.api.event.PluginMessageEvent;
import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.util.*;
import static com.imaginarycode.minecraft.redisbungee.api.util.serialize.MultiMapSerialization.*;
public class RedisBungeeListener implements Listener {
private final RedisBungeePlugin<ProxiedPlayer> plugin;
public RedisBungeeListener(RedisBungeePlugin<ProxiedPlayer> plugin) {
this.plugin = plugin;
}
@EventHandler
public void onPing(ProxyPingEvent event) {
if (!plugin.configuration().handleMotd()) return;
if (plugin.configuration().getExemptAddresses().contains(event.getConnection().getAddress().getAddress())) return;
ServerInfo forced = AbstractReconnectHandler.getForcedHost(event.getConnection());
if (forced != null && event.getConnection().getListener().isPingPassthrough()) return;
event.getResponse().getPlayers().setOnline(plugin.proxyDataManager().totalNetworkPlayers());
}
@SuppressWarnings("UnstableApiUsage")
@EventHandler
public void onPluginMessage(PluginMessageEvent event) {
if ((event.getTag().equals("legacy:redisbungee") || event.getTag().equals("RedisBungee")) && event.getSender() instanceof Server) {
final String currentChannel = event.getTag();
final byte[] data = Arrays.copyOf(event.getData(), event.getData().length);
plugin.executeAsync(() -> {
ByteArrayDataInput in = ByteStreams.newDataInput(data);
String subchannel = in.readUTF();
ByteArrayDataOutput out = ByteStreams.newDataOutput();
String type;
switch (subchannel) {
case "PlayerList" -> {
out.writeUTF("PlayerList");
Set<UUID> original = Collections.emptySet();
type = in.readUTF();
if (type.equals("ALL")) {
out.writeUTF("ALL");
original = plugin.proxyDataManager().networkPlayers();
} else {
out.writeUTF(type);
try {
original = plugin.getAbstractRedisBungeeApi().getPlayersOnServer(type);
} catch (IllegalArgumentException ignored) {
}
}
Set<String> players = new HashSet<>();
for (UUID uuid : original)
players.add(plugin.getUuidTranslator().getNameFromUuid(uuid, false));
out.writeUTF(Joiner.on(',').join(players));
}
case "PlayerCount" -> {
out.writeUTF("PlayerCount");
type = in.readUTF();
if (type.equals("ALL")) {
out.writeUTF("ALL");
out.writeInt(plugin.proxyDataManager().totalNetworkPlayers());
} else {
out.writeUTF(type);
try {
out.writeInt(plugin.getAbstractRedisBungeeApi().getPlayersOnServer(type).size());
} catch (IllegalArgumentException e) {
out.writeInt(0);
}
}
}
case "LastOnline" -> {
String user = in.readUTF();
out.writeUTF("LastOnline");
out.writeUTF(user);
out.writeLong(plugin.getAbstractRedisBungeeApi().getLastOnline(Objects.requireNonNull(plugin.getUuidTranslator().getTranslatedUuid(user, true))));
}
case "ServerPlayers" -> {
String type1 = in.readUTF();
out.writeUTF("ServerPlayers");
Multimap<String, UUID> multimap = plugin.getAbstractRedisBungeeApi().getServerToPlayers();
boolean includesUsers;
switch (type1) {
case "COUNT" -> includesUsers = false;
case "PLAYERS" -> includesUsers = true;
default -> {
// TODO: Should I raise an error?
return;
}
}
out.writeUTF(type1);
if (includesUsers) {
Multimap<String, String> human = HashMultimap.create();
for (Map.Entry<String, UUID> entry : multimap.entries()) {
human.put(entry.getKey(), plugin.getUuidTranslator().getNameFromUuid(entry.getValue(), false));
}
serializeMultimap(human, true, out);
} else {
serializeMultiset(multimap.keys(), out);
}
}
case "Proxy" -> {
out.writeUTF("Proxy");
out.writeUTF(plugin.configuration().getProxyId());
}
case "PlayerProxy" -> {
String username = in.readUTF();
out.writeUTF("PlayerProxy");
out.writeUTF(username);
out.writeUTF(plugin.getAbstractRedisBungeeApi().getProxy(Objects.requireNonNull(plugin.getUuidTranslator().getTranslatedUuid(username, true))));
}
default -> {
return;
}
}
((Server) event.getSender()).sendData(currentChannel, out.toByteArray());
});
}
}
@EventHandler
public void onServerConnectEvent(ServerConnectEvent event) {
if (event.getReason() == ServerConnectEvent.Reason.JOIN_PROXY && plugin.configuration().handleReconnectToLastServer()) {
ProxiedPlayer player = event.getPlayer();
String lastServer = plugin.playerDataManager().getLastServerFor(event.getPlayer().getUniqueId());
if (lastServer == null) return;
player.sendMessage(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().serverConnecting(player.getLocale(), lastServer)));
ServerInfo serverInfo = ProxyServer.getInstance().getServerInfo(lastServer);
if (serverInfo == null) {
player.sendMessage(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().serverNotFound(player.getLocale(), lastServer)));
return;
}
event.setTarget(serverInfo);
}
}
}

View File

@@ -0,0 +1,52 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.events;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerChangedServerNetworkEvent;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* This event is sent when a player connects to a new server. RedisBungee sends the event only when
* the proxy the player has been connected to is different than the local proxy.
* <p>
* This event corresponds to {@link net.md_5.bungee.api.event.ServerConnectedEvent}, and is fired
* asynchronously.
*
* @since 0.3.4
*/
public class PlayerChangedServerNetworkEvent extends Event implements IPlayerChangedServerNetworkEvent {
private final UUID uuid;
private final String previousServer;
private final String server;
public PlayerChangedServerNetworkEvent(UUID uuid, String previousServer, String server) {
this.uuid = uuid;
this.previousServer = previousServer;
this.server = server;
}
@Override
public UUID getUuid() {
return uuid;
}
@Override
public String getServer() {
return server;
}
@Override
public String getPreviousServer() {
return previousServer;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.events;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* This event is sent when a player joins the network. RedisBungee sends the event only when
* the proxy the player has been connected to is different than the local proxy.
* <p>
* This event corresponds to {@link net.md_5.bungee.api.event.PostLoginEvent}, and is fired
* asynchronously.
*
* @since 0.3.4
*/
public class PlayerJoinedNetworkEvent extends Event implements IPlayerJoinedNetworkEvent {
private final UUID uuid;
public PlayerJoinedNetworkEvent(UUID uuid) {
this.uuid = uuid;
}
@Override
public UUID getUuid() {
return uuid;
}
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.events;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent;
import net.md_5.bungee.api.plugin.Event;
import java.util.UUID;
/**
* This event is sent when a player disconnects. RedisBungee sends the event only when
* the proxy the player has been connected to is different than the local proxy.
* <p>
* This event corresponds to {@link net.md_5.bungee.api.event.PlayerDisconnectEvent}, and is fired
* asynchronously.
*
* @since 0.3.4
*/
public class PlayerLeftNetworkEvent extends Event implements IPlayerLeftNetworkEvent {
private final UUID uuid;
public PlayerLeftNetworkEvent(UUID uuid) {
this.uuid = uuid;
}
@Override
public UUID getUuid() {
return uuid;
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright (c) 2013-present RedisBungee contributors
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
*
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.imaginarycode.minecraft.redisbungee.events;
import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent;
import net.md_5.bungee.api.plugin.Event;
/**
* This event is posted when a PubSub message is received.
* <p>
* <strong>Warning</strong>: This event is fired in a separate thread!
*
* @since 0.2.6
*/
public class PubSubMessageEvent extends Event implements IPubSubMessageEvent {
private final String channel;
private final String message;
public PubSubMessageEvent(String channel, String message) {
this.channel = channel;
this.message = message;
}
@Override
public String getChannel() {
return channel;
}
@Override
public String getMessage() {
return message;
}
}

View File

@@ -0,0 +1,6 @@
name: RedisBungee
main: com.imaginarycode.minecraft.redisbungee.RedisBungee
version: *{redisbungee.version}*
author: "astei, ProxioDev"
# This is used so that we can automatically override default BungeeCord behavior.
softDepends: ["cmd_find", "cmd_list"]