2
0
mirror of https://github.com/proxiodev/RedisBungee.git synced 2026-05-03 11:40:29 +00:00

61 Commits

Author SHA1 Message Date
4221ebb892 Update readme to reflect the new project name 2026-03-18 21:16:24 +04:00
d93076eb81 maintenance: jitpack and github action move to java 21 2026-03-17 00:35:29 +04:00
1d2c11c538 maintenance: velocity require java 21 now for 3.5.0 2026-03-17 00:31:36 +04:00
e495b11587 maintenance: fix javadocs of bungeecord and update to 5 instead of 4 2026-03-17 00:28:08 +04:00
b250776c82 maintenance: remove java @Nullable parameter from Configuration class 2026-03-17 00:18:01 +04:00
13cfe8db13 maintenance: move to blossom v2 and use indragit to get git info 2026-03-17 00:17:12 +04:00
d30c70c8c4 maintenance: update versions
blossom update to 2v include indragit
2026-03-17 00:15:36 +04:00
3aa76384c3 maintenance: update gradle wrapper 2026-03-17 00:14:10 +04:00
92c965bfc6 readd leagacy methods to bungeecord only 2025-02-24 23:20:02 +04:00
1fb429ea77 finishup bungeecord, move to mini message as serialzier 2025-02-22 19:04:06 +04:00
338297192c reimpl kick api using serialized messages instead, Move language to own module, depenedcies fixes 2025-02-22 17:57:06 +04:00
1d3bd7e101 remove depercated apis | begin removing adventure api from the main api 2025-02-22 15:43:49 +04:00
96c0dff8c1 debug command introduction 2025-02-22 15:05:43 +04:00
Pierre-Olivier GOIN
23aeb81308 database address isn't the same in player manager (#127)
Maintain the same name in the Redis database as in the ProxyDataManager.

redis-bungee -> redisbungee
2025-02-22 11:08:40 +04:00
Pierre-Olivier GOIN
c84b987b9e Duplicated RB-Velocity in Gradle Settings (#128) 2025-02-22 11:05:49 +04:00
8177260991 make platforms can't see each other when using same redis server and network id 2025-02-21 19:44:52 +04:00
287f037774 Remove generics used for events in PlayerData 2025-01-28 20:14:45 +04:00
c633f1a106 properly cache last online and its invalidation 2025-01-28 20:14:45 +04:00
9fd1da5f92 fix depenedcies being copied 2025-01-28 20:14:45 +04:00
0050575aff update okhttp 2025-01-28 20:14:45 +04:00
6eab4ef602 move gradle plugins to libs file 2025-01-28 20:14:44 +04:00
12acc16376 build system improvement & update adventure 2025-01-28 20:14:44 +04:00
8b9af8838d Fix methods of Bungeecord listener being private
seems like i forgot to check the bungeecord impl correctly.
2025-01-28 20:14:44 +04:00
Dawid Sawicki
81bf06e2df Allow to customize ping events priority via handle-motd-order (#108)
Currently, the bungee implementation is using NORMAL priority for the
ping event handler, while the velocity implementation is using LAST.
Regardless of which choice may be the better one, this is an
inconsistency that this patch addresses by using NORMAL as the default
for both platforms.

Additionally to addressing the inconsistency, this patch adds a new
config option `handle-motd-order` which uses velocity's event priority
nomenclature to allow configuring the behavior of the MOTD handling on
both platforms.

In cases where there is a MOTD plugin that incorrectly overrides a
player count using the local player count, one may choose to use order
LAST to override the value back to the global player count.

In cases where there is a MOTD plugin that relies on a player count
value from the ping response, one may choose to use order FIRST to make
sure the response will have the correct global player count.

Fixes https://github.com/ProxioDev/ValioBungee/issues/107
2025-01-28 20:14:44 +04:00
41b1dab8cc update velocity runner 2025-01-28 20:14:44 +04:00
a437db32b8 update gradle, update depends 2025-01-28 20:14:44 +04:00
2bd79f628e runWaterfall & Waterfall proxy EOL 2025-01-28 20:14:44 +04:00
93c1cd8e4c 0.13.0-SNAPSHOT 2025-01-28 20:14:44 +04:00
f27d54beb8 0.12.6 2025-01-28 12:09:06 +04:00
91ea0b08dc relocate adventure api in bungeecord due collison with other plugins 2025-01-28 12:08:10 +04:00
199c1c7135 0.12.5 2024-09-28 12:34:23 +04:00
dab5f26e2c fix event double firing in velocity 2024-09-26 19:24:38 +04:00
c622bc7b63 move destroyProxyMembers to correct place
fixes null network id
2024-09-26 19:10:32 +04:00
881691a92d gradle wrapper upgrade, update bungeecord 2024-09-26 19:09:51 +04:00
079606c9da include new branches name in github file 2024-09-26 16:08:43 +04:00
ea54a0bc49 Update gradle.yml 2024-09-26 16:05:17 +04:00
69e91c3e42 check if player is really on the proxy when connecting
this prevents logged in error if somehow proxy shutdowns at weird time
2024-09-26 13:43:33 +04:00
Joël | NoPermission
d8704c8a8f Fixed null when fetching server id. (#118)
(cherry picked from commit 219a4ab360)
2024-09-26 12:18:46 +04:00
Efe Kurban
981d42d4a8 Added null-check for server keys (#106)
Fixes https://github.com/ProxioDev/ValioBungee/issues/105

(cherry picked from commit be0c6be2aa)
2024-09-26 12:18:24 +04:00
e0bca62cdb reintroduce 1 hour cache 2024-05-18 15:02:14 +04:00
md5nake
9ebfafbeef Invalidate serversToPlayersCache on player updates (#103)
This closes #102
2024-05-18 14:59:24 +04:00
70eebdc9ec Revert "reintroduce 1 hour cache, remove servers to player cache due changes can happen fast."
This reverts commit e85e18dad8.
2024-05-18 14:58:02 +04:00
e85e18dad8 reintroduce 1 hour cache, remove servers to player cache due changes can happen fast. 2024-05-18 14:46:23 +04:00
995c9045df 0.12.4 | fix send command to proxies not executing on sender proxy 2024-05-16 02:57:49 +04:00
2485150ddc 0.12.3 2024-05-15 22:08:18 +04:00
32735466d6 Deprecate old apis for removal in 0.13.0 2024-05-14 20:52:45 +04:00
e8715e5399 ignore IllegalStateException thrown by ServerConnection class in velocity 2024-05-14 19:23:09 +04:00
71287055b4 fix javadocs x2 2024-05-13 02:43:47 +04:00
8b48736bc1 fix javadocs 2024-05-13 02:38:58 +04:00
a2e6aff4c2 remove java docs from proxy impl 2024-05-13 02:33:56 +04:00
7c1c1183cf update gitignore 2024-05-13 02:27:44 +04:00
7f35b64d93 stupid git 2024-05-13 02:00:31 +04:00
3dc3d80045 update github workflow 2024-05-13 01:56:38 +04:00
765e6fe122 redo module system 2024-05-13 01:54:50 +04:00
e8514b3e8b 0.12.3 snapshot 2024-05-13 01:02:29 +04:00
e1d401639e even more oops: why caches are set to 1 hour ._. 2024-05-07 20:42:33 +04:00
f8c304d441 oops: remove cache of last-online
i must forgotten to remove it during development
2024-05-07 20:37:16 +04:00
e6b789229c bump version 0.12.2 2024-05-06 21:30:55 +04:00
025b555457 maven publish commands aswell 2024-05-06 21:27:37 +04:00
7029552c02 clarify compatibility mode error 2024-05-06 15:24:10 +04:00
62007992a7 bump 0.12.2-snapshot 2024-05-06 15:20:34 +04:00
106 changed files with 1035 additions and 745 deletions

View File

@@ -5,9 +5,9 @@ name: RedisBungee Build
on: on:
push: push:
branches: [ main ] branches: [ stable, develop ]
pull_request: pull_request:
branches: [ main ] branches: [ stable, develop ]
jobs: jobs:
build: build:
@@ -16,27 +16,27 @@ jobs:
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
- name: Set up JDK 17 - name: Set up JDK 21
uses: actions/setup-java@v2 uses: actions/setup-java@v2
with: with:
java-version: '17' java-version: '21'
distribution: 'adopt' distribution: 'adopt'
- name: Build with gradle - name: Build with gradle
run: ./gradlew shadowJar run: ./gradlew shadowJar
- name: Upload Bungee - name: Upload Bungee
uses: actions/upload-artifact@v2.2.3 uses: actions/upload-artifact@v4.4.0
with: with:
# Artifact name # Artifact name
name: RedisBungee-Bungee name: RedisBungee-Bungee
# Destination path # Destination path
path: RedisBungee-Bungee/build/libs/* path: proxies/bungeecord/build/libs/*
- name: Upload Velocity - name: Upload Velocity
uses: actions/upload-artifact@v2.2.3 uses: actions/upload-artifact@v4.4.0
with: with:
name: RedisBungee-Velocity name: RedisBungee-Velocity
path: RedisBungee-Velocity/build/libs/* path: proxies/velocity/build/libs/*
- name: Upload API - name: Upload API
uses: actions/upload-artifact@v2.2.3 uses: actions/upload-artifact@v4.4.0
with: with:
name: RedisBungee-API name: RedisBungee-API
path: RedisBungee-API/build/libs/* path: api/build/libs/*

2
.gitignore vendored
View File

@@ -46,4 +46,4 @@ manifest.mf
javadoc javadoc
# run-server folders # run-server folders
*/run proxies/*/run

View File

@@ -1,9 +1,12 @@
# RedisBungee Limework's Fork # ValioBungee: The RedisBungee Limework's Fork
The original project of RedisBungee is no longer maintained, so we have forked the plugin. The original project of RedisBungee is no longer maintained, so we have forked the plugin.
RedisBungee uses [Redis](https://redis.io) with Java client [Jedis](https://github.com/redis/jedis/) RedisBungee uses [Redis](https://redis.io) with Java client [Jedis](https://github.com/redis/jedis/)
to Synchronize players data between [BungeeCord](https://github.com/SpigotMC/BungeeCord) to Synchronize players data between [BungeeCord](https://github.com/SpigotMC/BungeeCord)
or [Velocity*](https://github.com/PaperMC/Velocity) proxies or [Velocity*](https://github.com/PaperMC/Velocity) proxies
## Why different name?
Because from our current understanding we cant use Redis name due trademark restrictions.
so we settled with valiobungee. But it doesnt not effect any internals naming schemes like plugin id and so on.
## Downloads ## Downloads
@@ -11,7 +14,7 @@ or [Velocity*](https://github.com/PaperMC/Velocity) proxies
## Wiki ## Wiki
https://github.com/ProxioDev/RedisBungee/wiki https://github.com/ProxioDev/ValioBungee/wiki
## Support ## Support

View File

@@ -1,63 +0,0 @@
/*
* 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

@@ -1,84 +0,0 @@
plugins {
`java-library`
`maven-publish`
id("com.github.johnrengelman.shadow") version "8.1.1"
id("xyz.jpenilla.run-velocity") version "2.0.0"
}
dependencies {
api(project(":RedisBungee-API")) {
// Since velocity already includes guava / configurate exlude them
exclude("com.google.guava", "guava")
exclude("com.google.code.gson", "gson")
exclude("org.spongepowered", "configurate-yaml")
// exclude also adventure api
exclude("net.kyori", "adventure-api")
exclude("net.kyori", "adventure-text-serializer-gson")
exclude("net.kyori", "adventure-text-serializer-legacy")
exclude("net.kyori", "adventure-text-serializer-plain")
exclude("net.kyori", "adventure-text-minimessage")
}
compileOnly(libs.platform.velocity)
annotationProcessor(libs.platform.velocity)
implementation(project(":RedisBungee-Commands"))
implementation(libs.acf.velocity)
}
description = "RedisBungee Velocity 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://jd.papermc.io/velocity/3.0.0/", // velocity 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)
}
runVelocity {
velocityVersion("3.3.0-SNAPSHOT")
environment["REDISBUNGEE_PROXY_ID"] = "velocity-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()
}
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")
relocate("com.github.benmanes.caffeine", "com.imaginarycode.minecraft.redisbungee.internal.caffeine")
// acf shade
relocate("co.aikar.commands", "com.imaginarycode.minecraft.redisbungee.internal.acf.commands")
}
}
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -1,10 +1,10 @@
import java.time.Instant
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
plugins { plugins {
`java-library` `java-library`
`maven-publish` `maven-publish`
id("net.kyori.blossom") version "1.2.0" alias(libs.plugins.blossom)
alias(libs.plugins.indragit)
} }
@@ -12,31 +12,22 @@ dependencies {
api(libs.guava) api(libs.guava)
api(libs.jedis) api(libs.jedis)
api(libs.okhttp) api(libs.okhttp)
api(libs.configurate) api(libs.configurateV3)
api(libs.caffeine) api(libs.caffeine)
api(libs.adventure.api)
api(libs.adventure.gson)
api(libs.adventure.legacy)
api(libs.adventure.plain)
api(libs.adventure.miniMessage)
} }
description = "RedisBungee interfaces" description = "RedisBungee interfaces"
sourceSets {
main {
blossom { blossom {
replaceToken("@version@", "$version") javaSources {
// GIT property("version", "$version")
val commit: String; property("git-commit", indraGit.commit().toString())
val commitStdout = ByteArrayOutputStream() }
rootProject.exec { }
standardOutput = commitStdout
commandLine("git", "rev-parse", "HEAD")
} }
commit = "$commitStdout".replace("\n", "") // for some reason it adds new line so remove it.
commitStdout.close()
replaceToken("@git_commit@", commit)
} }
java { java {
withJavadocJar() withJavadocJar()
@@ -50,9 +41,9 @@ tasks {
options.use() options.use()
options.isDocFilesSubDirs = true options.isDocFilesSubDirs = true
val jedisVersion = libs.jedis.get().version val jedisVersion = libs.jedis.get().version
val configurateVersion = libs.configurate.get().version val configurateVersion = libs.configurateV3.get().version
val guavaVersion = libs.guava.get().version val guavaVersion = libs.guava.get().version
val adventureVersion = libs.adventure.plain.get().version val adventureVersion = libs.adventure.api.get().version
options.links( options.links(
"https://configurate.aoeu.xyz/$configurateVersion/apidocs/", // configurate "https://configurate.aoeu.xyz/$configurateVersion/apidocs/", // configurate
"https://javadoc.io/doc/redis.clients/jedis/$jedisVersion/", // jedis "https://javadoc.io/doc/redis.clients/jedis/$jedisVersion/", // jedis

View File

@@ -14,16 +14,10 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisClusterSummoner;
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisPooledSummoner;
import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner; import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner;
import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPooled;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.*; import java.util.*;
@@ -216,19 +210,6 @@ public abstract class AbstractRedisBungeeAPI {
return plugin.proxyDataManager().proxyId(); return plugin.proxyDataManager().proxyId();
} }
/**
* Get the current BungeeCord / Velocity proxy ID for this server.
*
* @return the current server ID
* @see #getAllServers()
* @since 0.2.5
* @deprecated to avoid confusion between A server and A proxy see #getProxyId()
*/
@Deprecated
public final String getServerId() {
return getProxyId();
}
/** /**
* Get all the linked proxies in this network. * Get all the linked proxies in this network.
* *
@@ -240,41 +221,6 @@ public abstract class AbstractRedisBungeeAPI {
return plugin.proxyDataManager().proxiesIds(); return plugin.proxyDataManager().proxiesIds();
} }
/**
* Get all the linked proxies in this network.
*
* @return the list of all proxies
* @see #getServerId()
* @since 0.2.5
* @deprecated to avoid confusion between A server and A proxy see see {@link #getAllProxies()}
*/
@Deprecated
public final List<String> getAllServers() {
return getAllProxies();
}
/**
* Register (a) PubSub channel(s), so that you may handle PubSubMessageEvent for it.
*
* @param channels the channels to register
* @since 0.3
* @deprecated No longer required
*/
@Deprecated
public final void registerPubSubChannels(String... channels) {
}
/**
* Unregister (a) PubSub channel(s).
*
* @param channels the channels to unregister
* @since 0.3
* @deprecated No longer required
*/
@Deprecated
public final void unregisterPubSubChannels(String... channels) {
}
/** /**
* Fetch a name from the specified UUID. UUIDs are cached locally and in Redis. This function falls back to Mojang * Fetch a name from the specified UUID. UUIDs are cached locally and in Redis. This function falls back to Mojang
* as a last resort, so calls <strong>may</strong> be blocking. * as a last resort, so calls <strong>may</strong> be blocking.
@@ -343,126 +289,6 @@ public abstract class AbstractRedisBungeeAPI {
} }
/**
* Kicks a player from the network
* calls {@link #getUuidFromName(String)} to get uuid
*
* @param playerName player name
* @param message kick message that player will see on kick
* @since 0.8.0
* @deprecated
*/
@Deprecated
public void kickPlayer(String playerName, String message) {
kickPlayer(getUuidFromName(playerName), message);
}
/**
* Kicks a player from the network
*
* @param playerUUID player name
* @param message kick message that player will see on kick
* @since 0.8.0
* @deprecated
*/
@Deprecated
public void kickPlayer(UUID playerUUID, String message) {
kickPlayer(playerUUID, Component.text(message));
}
/**
* Kicks a player from the network
* calls {@link #getUuidFromName(String)} to get uuid
*
* @param playerName player name
* @param message kick message that player will see on kick
* @since 0.12.0
*/
public void kickPlayer(String playerName, Component message) {
kickPlayer(getUuidFromName(playerName), message);
}
/**
* Kicks a player from the network
*
* @param playerUUID player name
* @param message kick message that player will see on kick
* @since 0.12.0
*/
public void kickPlayer(UUID playerUUID, Component message) {
this.plugin.playerDataManager().kickPlayer(playerUUID, message);
}
/**
* This gives you instance of Jedis
*
* @return {@link Jedis}
* @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#SINGLE}
* @see #getJedisPool()
* @since 0.7.0
*/
public Jedis requestJedis() {
if (getMode() == RedisBungeeMode.SINGLE) {
return getJedisPool().getResource();
} else {
throw new IllegalStateException("Mode is not " + RedisBungeeMode.SINGLE);
}
}
/**
* This gets Redis Bungee {@link JedisPool}
*
* @return {@link JedisPool}
* @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#SINGLE}
* @throws IllegalStateException if JedisPool compatibility mode is disabled in the config
* @since 0.6.5
*/
public JedisPool getJedisPool() {
if (getMode() == RedisBungeeMode.SINGLE) {
JedisPool jedisPool = ((JedisPooledSummoner) this.plugin.getSummoner()).getCompatibilityJedisPool();
if (jedisPool == null) {
throw new IllegalStateException("JedisPool compatibility mode is disabled");
}
return jedisPool;
} else {
throw new IllegalStateException("Mode is not " + RedisBungeeMode.SINGLE);
}
}
/**
* This gives you an instance of JedisCluster that can't be closed
* see {@link com.imaginarycode.minecraft.redisbungee.api.summoners.NotClosableJedisCluster}
*
* @return {@link redis.clients.jedis.JedisCluster}
* @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#CLUSTER}
* @since 0.8.0
*/
public JedisCluster requestClusterJedis() {
if (getMode() == RedisBungeeMode.CLUSTER) {
return ((JedisClusterSummoner) this.plugin.getSummoner()).obtainResource();
} else {
throw new IllegalStateException("Mode is not " + RedisBungeeMode.CLUSTER);
}
}
/**
* This gives you an instance of JedisPooled that can't be closed
* see {@link com.imaginarycode.minecraft.redisbungee.api.summoners.NotClosableJedisPooled}
*
* @return {@link redis.clients.jedis.JedisPooled}
* @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#SINGLE}
* @since 0.8.0
*/
public JedisPooled requestJedisPooled() {
if (getMode() == RedisBungeeMode.SINGLE) {
return ((JedisPooledSummoner) this.plugin.getSummoner()).obtainResource();
} else {
throw new IllegalStateException("Mode is not " + RedisBungeeMode.SINGLE);
}
}
/** /**
* returns Summoner class responsible for Single Jedis {@link redis.clients.jedis.JedisPooled} with {@link JedisPool}, Cluster Jedis {@link redis.clients.jedis.JedisCluster} handling * returns Summoner class responsible for Single Jedis {@link redis.clients.jedis.JedisPooled} with {@link JedisPool}, Cluster Jedis {@link redis.clients.jedis.JedisCluster} handling
* *
@@ -473,6 +299,28 @@ public abstract class AbstractRedisBungeeAPI {
return this.plugin.getSummoner(); return this.plugin.getSummoner();
} }
/**
* Kicks a player from the network using miniMessage
* calls {@link #getUuidFromName(String)} to get uuid
* <a href="https://docs.advntr.dev/minimessage/format.html">...</a>
* @param playerName player name
* @param miniMessage kick message that player will see on kick using minimessage as format
* @since 0.13.0
*/
public void kickPlayer(String playerName, String miniMessage) {
kickPlayer(getUuidFromName(playerName), miniMessage);
}
/**
* Kicks a player from the network
* <a href="https://docs.advntr.dev/minimessage/format.html">...</a>
* @param player player uuid
* @param miniMessage kick message that player will see on kick using minimessage as format
* @since 0.13.0
*/
public void kickPlayer(UUID player, String miniMessage) {
plugin.playerDataManager().serializedPlayerKick(player, miniMessage);
}
/** /**
* shows what mode is RedisBungee is on * shows what mode is RedisBungee is on

View File

@@ -13,11 +13,11 @@ package com.imaginarycode.minecraft.redisbungee;
public class Constants { public class Constants {
public final static String VERSION = "@version@"; public final static String VERSION = "{{ version }}";
public final static String GIT_COMMIT = "@git_commit@"; public final static String GIT_COMMIT = "{{ git-commit }}";
public static String getGithubCommitLink() { public static String getGithubCommitLink() {
return "https://github.com/ProxioDev/RedisBungee/commit/" + GIT_COMMIT; return "https://github.com/ProxioDev/ValioBungee/commit/" + GIT_COMMIT;
} }
} }

View File

@@ -16,11 +16,10 @@ import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.Multimap; import com.google.common.collect.Multimap;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerChangedServerNetworkEvent; 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.IPlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent; import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisPipelineTask; import com.imaginarycode.minecraft.redisbungee.api.tasks.RedisPipelineTask;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.json.JSONComponentSerializer;
import org.json.JSONObject; import org.json.JSONObject;
import redis.clients.jedis.ClusterPipeline; import redis.clients.jedis.ClusterPipeline;
import redis.clients.jedis.Pipeline; import redis.clients.jedis.Pipeline;
@@ -28,25 +27,22 @@ import redis.clients.jedis.Response;
import redis.clients.jedis.UnifiedJedis; import redis.clients.jedis.UnifiedJedis;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.HashMap; import java.util.*;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEvent, SC extends IPlayerChangedServerNetworkEvent, NJE extends IPlayerLeftNetworkEvent, CE> { public abstract class PlayerDataManager<P> {
protected final RedisBungeePlugin<P> plugin; protected final RedisBungeePlugin<P> plugin;
private final Object SERVERS_TO_PLAYERS_KEY = new Object();
private final UnifiedJedis unifiedJedis;
private final String proxyId;
private final String networkId;
private final LoadingCache<UUID, String> serverCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getServerFromRedis); private final LoadingCache<UUID, String> serverCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getServerFromRedis);
private final LoadingCache<UUID, String> lastServerCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getLastServerFromRedis); private final LoadingCache<UUID, String> lastServerCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getLastServerFromRedis);
private final LoadingCache<UUID, String> proxyCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getProxyFromRedis); private final LoadingCache<UUID, String> proxyCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getProxyFromRedis);
private final LoadingCache<UUID, InetAddress> ipCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getIpAddressFromRedis); private final LoadingCache<UUID, InetAddress> ipCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getIpAddressFromRedis);
private final LoadingCache<UUID, Long> lastOnlineCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getLastOnlineFromRedis); private final LoadingCache<UUID, Long> lastOnlineCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.HOURS).build(this::getLastOnlineFromRedis);
private final Object SERVERS_TO_PLAYERS_KEY = new Object();
private final LoadingCache<Object, Multimap<String, UUID>> serverToPlayersCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).build(this::serversToPlayersBuilder); private final LoadingCache<Object, Multimap<String, UUID>> serverToPlayersCache = Caffeine.newBuilder().expireAfterWrite(10, TimeUnit.MINUTES).build(this::serversToPlayersBuilder);
private final UnifiedJedis unifiedJedis;
private final String proxyId;
private final String networkId;
public PlayerDataManager(RedisBungeePlugin<P> plugin) { public PlayerDataManager(RedisBungeePlugin<P> plugin) {
this.plugin = plugin; this.plugin = plugin;
@@ -57,23 +53,27 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
// handle network wide // handle network wide
// server change // server change
public abstract void onPlayerChangedServerNetworkEvent(SC event); // public void onPlayerChangedServerNetworkEvent
public abstract void onNetworkPlayerQuit(NJE event); // public void onNetworkPlayerQuit
// public void onNetworkPlayerJoin
// local events // local events
public abstract void onPubSubMessageEvent(PS event); // public void onPubSubMessageEvent
public abstract void onServerConnectedEvent(CE event); // public void onServerConnectedEvent
public abstract void onLoginEvent(LE event); // public void onLoginEvent
public abstract void onDisconnectEvent(DE event);
// public void onDisconnectEvent
protected void handleNetworkPlayerServerChange(IPlayerChangedServerNetworkEvent event) { protected void handleNetworkPlayerServerChange(IPlayerChangedServerNetworkEvent event) {
this.serverCache.invalidate(event.getUuid()); this.serverCache.invalidate(event.getUuid());
this.lastServerCache.invalidate(event.getUuid()); this.lastServerCache.invalidate(event.getUuid());
//TODO: We could also rely on redisbungee-serverchange pubsub messages to update the cache in-place without querying redis. That would be a lot more efficient.
this.serverToPlayersCache.invalidate(SERVERS_TO_PLAYERS_KEY);
} }
protected void handleNetworkPlayerQuit(IPlayerLeftNetworkEvent event) { protected void handleNetworkPlayerQuit(IPlayerLeftNetworkEvent event) {
@@ -81,53 +81,49 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
this.serverCache.invalidate(event.getUuid()); this.serverCache.invalidate(event.getUuid());
this.ipCache.invalidate(event.getUuid()); this.ipCache.invalidate(event.getUuid());
this.lastOnlineCache.invalidate(event.getUuid()); this.lastOnlineCache.invalidate(event.getUuid());
//TODO: We could also rely on redisbungee-serverchange pubsub messages to update the cache in-place without querying redis. That would be a lot more efficient.
this.serverToPlayersCache.invalidate(SERVERS_TO_PLAYERS_KEY);
} }
protected void handleNetworkPlayerJoin(IPlayerJoinedNetworkEvent event) {
this.proxyCache.invalidate(event.getUuid());
this.serverCache.invalidate(event.getUuid());
this.ipCache.invalidate(event.getUuid());
this.lastOnlineCache.invalidate(event.getUuid());
//TODO: We could also rely on redisbungee-serverchange pubsub messages to update the cache in-place without querying redis. That would be a lot more efficient.
this.serverToPlayersCache.invalidate(SERVERS_TO_PLAYERS_KEY);
}
protected void handlePubSubMessageEvent(IPubSubMessageEvent event) { protected void handlePubSubMessageEvent(IPubSubMessageEvent event) {
// kick api switch (event.getChannel()) {
if (event.getChannel().equals("redisbungee-kick")) { case "redisbungee-serverchange" -> {
JSONObject data = new JSONObject(event.getMessage()); JSONObject data = new JSONObject(event.getMessage());
String proxy = data.getString("proxy");
if (proxy.equals(this.proxyId)) {
return;
}
UUID uuid = UUID.fromString(data.getString("uuid"));
String message = data.getString("message");
plugin.handlePlatformKick(uuid, COMPONENT_SERIALIZER.deserialize(message));
return;
}
if (event.getChannel().equals("redisbungee-serverchange")) {
JSONObject data = new JSONObject(event.getMessage());
String proxy = data.getString("proxy");
if (proxy.equals(this.proxyId)) {
return;
}
UUID uuid = UUID.fromString(data.getString("uuid")); UUID uuid = UUID.fromString(data.getString("uuid"));
String from = null; String from = null;
if (data.has("from")) from = data.getString("from"); if (data.has("from")) from = data.getString("from");
String to = data.getString("to"); String to = data.getString("to");
plugin.fireEvent(plugin.createPlayerChangedServerNetworkEvent(uuid, from, to)); plugin.fireEvent(plugin.createPlayerChangedServerNetworkEvent(uuid, from, to));
return;
} }
if (event.getChannel().equals("redisbungee-player-join")) { case "redisbungee-player-join" -> {
JSONObject data = new JSONObject(event.getMessage()); JSONObject data = new JSONObject(event.getMessage());
String proxy = data.getString("proxy");
if (proxy.equals(this.proxyId)) {
return;
}
UUID uuid = UUID.fromString(data.getString("uuid")); UUID uuid = UUID.fromString(data.getString("uuid"));
plugin.fireEvent(plugin.createPlayerJoinedNetworkEvent(uuid)); plugin.fireEvent(plugin.createPlayerJoinedNetworkEvent(uuid));
return;
} }
if (event.getChannel().equals("redisbungee-player-leave")) { case "redisbungee-player-leave" -> {
JSONObject data = new JSONObject(event.getMessage()); JSONObject data = new JSONObject(event.getMessage());
String proxy = data.getString("proxy");
if (proxy.equals(this.proxyId)) {
return;
}
UUID uuid = UUID.fromString(data.getString("uuid")); UUID uuid = UUID.fromString(data.getString("uuid"));
plugin.fireEvent(plugin.createPlayerLeftNetworkEvent(uuid)); plugin.fireEvent(plugin.createPlayerLeftNetworkEvent(uuid));
} }
case "redisbungee-player-kick" -> {
JSONObject data = new JSONObject(event.getMessage());
UUID uuid = UUID.fromString(data.getString("uuid"));
String message = data.getString("serialized-message");
handleSerializedKick(uuid, message);
}
}
} }
@@ -142,23 +138,28 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
handleServerChangeRedis(uuid, to); handleServerChangeRedis(uuid, to);
} }
private final JSONComponentSerializer COMPONENT_SERIALIZER =JSONComponentSerializer.json(); // must check if player is on the local proxy
// https://docs.advntr.dev/minimessage/index.html
// implemented downstream in Velocity and Bungeecord
protected abstract boolean handleSerializedKick(UUID player, String serializedMiniMessage);
public void kickPlayer(UUID uuid, Component message) { // https://docs.advntr.dev/minimessage/index.html
if (!plugin.handlePlatformKick(uuid, message)) { // handle locally before SENDING a message // implemented downstream in Velocity and Bungeecord
// called by kickPlayer in each impl of this class `NOT OVERRIDE`
public void serializedPlayerKick(UUID player, String serializedMiniMessage) {
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("proxy", this.proxyId); data.put("proxy", this.proxyId);
data.put("uuid", uuid); data.put("uuid", player);
data.put("message", COMPONENT_SERIALIZER.serialize(message)); data.put("serialized-message", serializedMiniMessage);
plugin.proxyDataManager().sendChannelMessage("redisbungee-kick", data.toString()); if (!handleSerializedKick(player, serializedMiniMessage))
} plugin.proxyDataManager().sendChannelMessage("redisbungee-player-kick", data.toString());
} }
private void handleServerChangeRedis(UUID uuid, String server) { private void handleServerChangeRedis(UUID uuid, String server) {
Map<String, String> data = new HashMap<>(); Map<String, String> data = new HashMap<>();
data.put("server", server); data.put("server", server);
data.put("last-server", server); data.put("last-server", server);
unifiedJedis.hset("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", data); unifiedJedis.hset("redisbungee::" + this.networkId + "::player::" + uuid + "::data", data);
} }
protected void addPlayer(final UUID uuid, final String name, final InetAddress inetAddress) { protected void addPlayer(final UUID uuid, final String name, final InetAddress inetAddress) {
@@ -166,7 +167,7 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
redisData.put("last-online", String.valueOf(0)); redisData.put("last-online", String.valueOf(0));
redisData.put("proxy", this.proxyId); redisData.put("proxy", this.proxyId);
redisData.put("ip", inetAddress.getHostAddress()); redisData.put("ip", inetAddress.getHostAddress());
unifiedJedis.hset("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", redisData); unifiedJedis.hset("redisbungee::" + this.networkId + "::player::" + uuid + "::data", redisData);
plugin.getUuidTranslator().persistInfo(name, uuid, this.unifiedJedis); plugin.getUuidTranslator().persistInfo(name, uuid, this.unifiedJedis);
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("proxy", this.proxyId); data.put("proxy", this.proxyId);
@@ -177,8 +178,8 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
} }
protected void removePlayer(UUID uuid) { protected void removePlayer(UUID uuid) {
unifiedJedis.hset("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", "last-online", String.valueOf(System.currentTimeMillis())); unifiedJedis.hset("redisbungee::" + this.networkId + "::player::" + uuid + "::data", "last-online", String.valueOf(System.currentTimeMillis()));
unifiedJedis.hdel("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", "server", "proxy", "ip"); unifiedJedis.hdel("redisbungee::" + this.networkId + "::player::" + uuid + "::data", "server", "proxy", "ip");
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
data.put("proxy", this.proxyId); data.put("proxy", this.proxyId);
data.put("uuid", uuid); data.put("uuid", uuid);
@@ -189,25 +190,25 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
protected String getProxyFromRedis(UUID uuid) { protected String getProxyFromRedis(UUID uuid) {
return unifiedJedis.hget("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", "proxy"); return unifiedJedis.hget("redisbungee::" + this.networkId + "::player::" + uuid + "::data", "proxy");
} }
protected String getServerFromRedis(UUID uuid) { protected String getServerFromRedis(UUID uuid) {
return unifiedJedis.hget("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", "server"); return unifiedJedis.hget("redisbungee::" + this.networkId + "::player::" + uuid + "::data", "server");
} }
protected String getLastServerFromRedis(UUID uuid) { protected String getLastServerFromRedis(UUID uuid) {
return unifiedJedis.hget("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", "last-server"); return unifiedJedis.hget("redisbungee::" + this.networkId + "::player::" + uuid + "::data", "last-server");
} }
protected InetAddress getIpAddressFromRedis(UUID uuid) { protected InetAddress getIpAddressFromRedis(UUID uuid) {
String ip = unifiedJedis.hget("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", "ip"); String ip = unifiedJedis.hget("redisbungee::" + this.networkId + "::player::" + uuid + "::data", "ip");
if (ip == null) return null; if (ip == null) return null;
return InetAddresses.forString(ip); return InetAddresses.forString(ip);
} }
protected long getLastOnlineFromRedis(UUID uuid) { protected long getLastOnlineFromRedis(UUID uuid) {
String unixString = unifiedJedis.hget("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", "last-online"); String unixString = unifiedJedis.hget("redisbungee::" + this.networkId + "::player::" + uuid + "::data", "last-online");
if (unixString == null) return -1; if (unixString == null) return -1;
return Long.parseLong(unixString); return Long.parseLong(unixString);
} }
@@ -215,6 +216,7 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
public String getLastServerFor(UUID uuid) { public String getLastServerFor(UUID uuid) {
return this.lastServerCache.get(uuid); return this.lastServerCache.get(uuid);
} }
public String getServerFor(UUID uuid) { public String getServerFor(UUID uuid) {
return this.serverCache.get(uuid); return this.serverCache.get(uuid);
} }
@@ -245,10 +247,17 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
public Multimap<String, UUID> doPooledPipeline(Pipeline pipeline) { public Multimap<String, UUID> doPooledPipeline(Pipeline pipeline) {
HashMap<UUID, Response<String>> responses = new HashMap<>(); HashMap<UUID, Response<String>> responses = new HashMap<>();
for (UUID uuid : uuids) { for (UUID uuid : uuids) {
responses.put(uuid, pipeline.hget("redis-bungee::" + networkId + "::player::" + uuid + "::data", "server")); Optional.ofNullable(pipeline.hget("redisbungee::" + networkId + "::player::" + uuid + "::data", "server")).ifPresent(stringResponse -> {
responses.put(uuid, stringResponse);
});
} }
pipeline.sync(); pipeline.sync();
responses.forEach((uuid, response) -> builder.put(response.get(), uuid)); responses.forEach((uuid, response) -> {
String key = response.get();
if (key == null) return;
builder.put(key, uuid);
});
return builder.build(); return builder.build();
} }
@@ -256,10 +265,16 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
public Multimap<String, UUID> clusterPipeline(ClusterPipeline pipeline) { public Multimap<String, UUID> clusterPipeline(ClusterPipeline pipeline) {
HashMap<UUID, Response<String>> responses = new HashMap<>(); HashMap<UUID, Response<String>> responses = new HashMap<>();
for (UUID uuid : uuids) { for (UUID uuid : uuids) {
responses.put(uuid, pipeline.hget("redis-bungee::" + networkId + "::player::" + uuid + "::data", "server")); Optional.ofNullable(pipeline.hget("redisbungee::" + networkId + "::player::" + uuid + "::data", "server")).ifPresent(stringResponse -> {
responses.put(uuid, stringResponse);
});
} }
pipeline.sync(); pipeline.sync();
responses.forEach((uuid, response) -> builder.put(response.get(), uuid)); responses.forEach((uuid, response) -> {
String key = response.get();
if (key == null) return;
builder.put(key, uuid);
});
return builder.build(); return builder.build();
} }
}.call(); }.call();

View File

@@ -66,9 +66,9 @@ public abstract class ProxyDataManager implements Runnable {
this.plugin = plugin; this.plugin = plugin;
this.proxyId = this.plugin.configuration().getProxyId(); this.proxyId = this.plugin.configuration().getProxyId();
this.unifiedJedis = plugin.getSummoner().obtainResource(); this.unifiedJedis = plugin.getSummoner().obtainResource();
this.destroyProxyMembers();
this.networkId = plugin.configuration().networkId(); this.networkId = plugin.configuration().networkId();
this.STREAM_ID = "network-" + this.networkId + "-redisbungee-stream"; this.STREAM_ID = "network-" + this.networkId + "-redisbungee-stream";
this.destroyProxyMembers();
} }
public abstract Set<UUID> getLocalOnlineUUIDs(); public abstract Set<UUID> getLocalOnlineUUIDs();
@@ -82,18 +82,27 @@ public abstract class ProxyDataManager implements Runnable {
return getProxyMembers(proxyId); return getProxyMembers(proxyId);
} }
// this skip checking if proxy is and its package private
// due proxy shutdown shenanigans
public boolean isPlayerTrulyOnProxy(String proxyId, UUID uuid) {
return unifiedJedis.sismember("redisbungee::" + this.networkId + "::proxies::" + proxyId + "::online-players", uuid.toString());
}
public List<String> proxiesIds() { public List<String> proxiesIds() {
return Collections.list(this.heartbeats.keys()); return Collections.list(this.heartbeats.keys());
} }
public synchronized void sendCommandTo(String proxyToRun, String command) { public synchronized void sendCommandTo(String proxyToRun, String command) {
if (isClosed()) return; if (isClosed()) return;
if (proxyToRun.equals("allservers") || proxyToRun.equals(this.proxyId())) {
handlePlatformCommandExecution(command);
}
publishPayload(new RunCommandPayload(this.proxyId, proxyToRun, command)); publishPayload(new RunCommandPayload(this.proxyId, proxyToRun, command));
} }
public synchronized void sendChannelMessage(String channel, String message) { public synchronized void sendChannelMessage(String channel, String message) {
if (isClosed()) return; if (isClosed()) return;
this.plugin.fireEvent(this.plugin.createPubSubEvent(channel, message));
publishPayload(new PubSubPayload(this.proxyId, channel, message)); publishPayload(new PubSubPayload(this.proxyId, channel, message));
} }
@@ -190,7 +199,7 @@ public abstract class ProxyDataManager implements Runnable {
Set<UUID> storedRedisUuids = getProxyMembers(this.proxyId); Set<UUID> storedRedisUuids = getProxyMembers(this.proxyId);
if (!localOnlineUUIDs.equals(storedRedisUuids)) { if (!localOnlineUUIDs.equals(storedRedisUuids)) {
plugin.logWarn("De-synced playerS set detected correcting...."); plugin.logWarn("De-synced players set detected correcting....");
Set<UUID> add = new HashSet<>(localOnlineUUIDs); Set<UUID> add = new HashSet<>(localOnlineUUIDs);
Set<UUID> remove = new HashSet<>(storedRedisUuids); Set<UUID> remove = new HashSet<>(storedRedisUuids);
add.removeAll(storedRedisUuids); add.removeAll(storedRedisUuids);

View File

@@ -11,12 +11,10 @@
package com.imaginarycode.minecraft.redisbungee.api; package com.imaginarycode.minecraft.redisbungee.api;
import com.imaginarycode.minecraft.redisbungee.AbstractRedisBungeeAPI; import com.imaginarycode.minecraft.redisbungee.AbstractRedisBungeeAPI;
import com.imaginarycode.minecraft.redisbungee.api.config.LangConfiguration;
import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration; import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration;
import com.imaginarycode.minecraft.redisbungee.api.events.EventsPlatform; import com.imaginarycode.minecraft.redisbungee.api.events.EventsPlatform;
import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner; import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner;
import com.imaginarycode.minecraft.redisbungee.api.util.uuid.UUIDTranslator; import com.imaginarycode.minecraft.redisbungee.api.util.uuid.UUIDTranslator;
import net.kyori.adventure.text.Component;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.UUID; import java.util.UUID;
@@ -55,8 +53,6 @@ public interface RedisBungeePlugin<P> extends EventsPlatform {
RedisBungeeConfiguration configuration(); RedisBungeeConfiguration configuration();
LangConfiguration langConfiguration();
Summoner<?> getSummoner(); Summoner<?> getSummoner();
RedisBungeeMode getRedisBungeeMode(); RedisBungeeMode getRedisBungeeMode();
@@ -65,7 +61,7 @@ public interface RedisBungeePlugin<P> extends EventsPlatform {
ProxyDataManager proxyDataManager(); ProxyDataManager proxyDataManager();
PlayerDataManager<P, ?, ?, ?, ?, ?, ?> playerDataManager(); PlayerDataManager<P> playerDataManager();
UUIDTranslator getUuidTranslator(); UUIDTranslator getUuidTranslator();
@@ -77,11 +73,8 @@ public interface RedisBungeePlugin<P> extends EventsPlatform {
UUID getPlayerUUID(String player); UUID getPlayerUUID(String player);
String getPlayerName(UUID player); String getPlayerName(UUID player);
boolean handlePlatformKick(UUID uuid, Component message);
String getPlayerServerName(P player); String getPlayerServerName(P player);
boolean isPlayerOnAServer(P player); boolean isPlayerOnAServer(P player);
@@ -92,5 +85,5 @@ public interface RedisBungeePlugin<P> extends EventsPlatform {
void executeAsyncAfter(Runnable runnable, TimeUnit timeUnit, int time); void executeAsyncAfter(Runnable runnable, TimeUnit timeUnit, int time);
String platformId();
} }

View File

@@ -0,0 +1,17 @@
/*
* 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.api.config;
public enum HandleMotdOrder {
FIRST,
NORMAL,
LAST
}

View File

@@ -13,7 +13,6 @@ package com.imaginarycode.minecraft.redisbungee.api.config;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.net.InetAddresses; import com.google.common.net.InetAddresses;
import javax.annotation.Nullable;
import java.net.InetAddress; import java.net.InetAddress;
import java.util.List; import java.util.List;
@@ -25,12 +24,13 @@ public class RedisBungeeConfiguration {
private final boolean handleReconnectToLastServer; private final boolean handleReconnectToLastServer;
private final boolean handleMotd; private final boolean handleMotd;
private final HandleMotdOrder handleMotdOrder;
private final CommandsConfiguration commandsConfiguration; private final CommandsConfiguration commandsConfiguration;
private final String networkId; private final String networkId;
public RedisBungeeConfiguration(String networkId, String proxyId, List<String> exemptAddresses, boolean kickWhenOnline, boolean handleReconnectToLastServer, boolean handleMotd, CommandsConfiguration commandsConfiguration) { public RedisBungeeConfiguration(String networkId, String proxyId, List<String> exemptAddresses, boolean kickWhenOnline, boolean handleReconnectToLastServer, boolean handleMotd, HandleMotdOrder handleMotdOrder, CommandsConfiguration commandsConfiguration) {
this.proxyId = proxyId; this.proxyId = proxyId;
ImmutableList.Builder<InetAddress> addressBuilder = ImmutableList.builder(); ImmutableList.Builder<InetAddress> addressBuilder = ImmutableList.builder();
for (String s : exemptAddresses) { for (String s : exemptAddresses) {
@@ -40,6 +40,7 @@ public class RedisBungeeConfiguration {
this.kickWhenOnline = kickWhenOnline; this.kickWhenOnline = kickWhenOnline;
this.handleReconnectToLastServer = handleReconnectToLastServer; this.handleReconnectToLastServer = handleReconnectToLastServer;
this.handleMotd = handleMotd; this.handleMotd = handleMotd;
this.handleMotdOrder = handleMotdOrder;
this.commandsConfiguration = commandsConfiguration; this.commandsConfiguration = commandsConfiguration;
this.networkId = networkId; this.networkId = networkId;
} }
@@ -60,12 +61,16 @@ public class RedisBungeeConfiguration {
return this.handleMotd; return this.handleMotd;
} }
public HandleMotdOrder handleMotdOrder() {
return handleMotdOrder;
}
public boolean handleReconnectToLastServer() { public boolean handleReconnectToLastServer() {
return this.handleReconnectToLastServer; return this.handleReconnectToLastServer;
} }
public record CommandsConfiguration(boolean redisbungeeEnabled, boolean redisbungeeLegacyEnabled, public record CommandsConfiguration(boolean redisbungeeEnabled, boolean redisbungeeLegacyEnabled,
@Nullable LegacySubCommandsConfiguration legacySubCommandsConfiguration) { LegacySubCommandsConfiguration legacySubCommandsConfiguration) {
} }

View File

@@ -14,6 +14,7 @@ package com.imaginarycode.minecraft.redisbungee.api.config.loaders;
import com.google.common.reflect.TypeToken; import com.google.common.reflect.TypeToken;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.config.HandleMotdOrder;
import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration; import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration;
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisClusterSummoner; import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisClusterSummoner;
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisPooledSummoner; import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisPooledSummoner;
@@ -96,14 +97,25 @@ public interface ConfigLoader extends GenericConfigLoader {
} }
plugin.logInfo("Loaded network id " + networkId); plugin.logInfo("Loaded network id " + networkId);
// TO avoid proxies from different platforms from seeing each other.
networkId = plugin.platformId() + "-" + networkId;
plugin.logInfo("Platform is {} so network id is now is {}", plugin.platformId(), networkId);
boolean reconnectToLastServer = node.getNode("reconnect-to-last-server").getBoolean(); boolean reconnectToLastServer = node.getNode("reconnect-to-last-server").getBoolean();
boolean handleMotd = node.getNode("handle-motd").getBoolean(true); boolean handleMotd = node.getNode("handle-motd").getBoolean(true);
plugin.logInfo("handle reconnect to last server: {}", reconnectToLastServer); plugin.logInfo("handle reconnect to last server: {}", reconnectToLastServer);
plugin.logInfo("handle motd: {}", handleMotd); plugin.logInfo("handle motd: {}", handleMotd);
HandleMotdOrder handleMotdOrder = HandleMotdOrder.NORMAL;
String handleMotdOrderName = node.getNode("handle-motd-priority").getString();
if (handleMotdOrderName != null) {
try {
handleMotdOrder = HandleMotdOrder.valueOf(handleMotdOrderName.toUpperCase(Locale.ROOT));
} catch (IllegalArgumentException e) {
plugin.logWarn("handle motd order value '{}' is unsupported (allowed: {})", handleMotdOrderName, HandleMotdOrder.values());
}
}
plugin.logInfo("handle motd order: {}", handleMotdOrder);
// commands // commands
boolean redisBungeeEnabled = node.getNode("commands", "redisbungee", "enabled").getBoolean(true); boolean redisBungeeEnabled = node.getNode("commands", "redisbungee", "enabled").getBoolean(true);
@@ -130,7 +142,8 @@ public interface ConfigLoader extends GenericConfigLoader {
boolean installPlist = node.getNode("commands", "redisbungee-legacy", "subcommands", "plist", "install").getBoolean(false); boolean installPlist = node.getNode("commands", "redisbungee-legacy", "subcommands", "plist", "install").getBoolean(false);
RedisBungeeConfiguration configuration = new RedisBungeeConfiguration(networkId, proxyId, exemptAddresses, kickWhenOnline, reconnectToLastServer, handleMotd, new RedisBungeeConfiguration.CommandsConfiguration( RedisBungeeConfiguration configuration = new RedisBungeeConfiguration(networkId, proxyId, exemptAddresses, kickWhenOnline, reconnectToLastServer, handleMotd, handleMotdOrder,
new RedisBungeeConfiguration.CommandsConfiguration(
redisBungeeEnabled, redisBungeeLegacyEnabled, redisBungeeEnabled, redisBungeeLegacyEnabled,
new RedisBungeeConfiguration.LegacySubCommandsConfiguration( new RedisBungeeConfiguration.LegacySubCommandsConfiguration(
findEnabled, glistEnabled, ipEnabled, findEnabled, glistEnabled, ipEnabled,

View File

@@ -13,28 +13,7 @@ package com.imaginarycode.minecraft.redisbungee.api.util.uuid;
import java.util.Calendar; import java.util.Calendar;
import java.util.UUID; import java.util.UUID;
public class CachedUUIDEntry { public record CachedUUIDEntry(String name, UUID uuid, Calendar expiry) {
private final String name;
private final UUID uuid;
private final Calendar expiry;
public CachedUUIDEntry(String name, UUID uuid, Calendar expiry) {
this.name = name;
this.uuid = uuid;
this.expiry = expiry;
}
public String getName() {
return name;
}
public UUID getUuid() {
return uuid;
}
public Calendar getExpiry() {
return expiry;
}
public boolean expired() { public boolean expired() {
return Calendar.getInstance().after(expiry); return Calendar.getInstance().after(expiry);

View File

@@ -12,9 +12,9 @@ package com.imaginarycode.minecraft.redisbungee.api.util.uuid;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.JsonObject; import com.google.gson.JsonObject;
import com.squareup.okhttp.OkHttpClient; import okhttp3.OkHttpClient;
import com.squareup.okhttp.Request; import okhttp3.Request;
import com.squareup.okhttp.ResponseBody; import okhttp3.ResponseBody;
import java.io.IOException; import java.io.IOException;
import java.util.Collections; import java.util.Collections;
@@ -22,13 +22,9 @@ import java.util.List;
import java.util.UUID; import java.util.UUID;
public class NameFetcher { public class NameFetcher {
private static OkHttpClient httpClient; private static final OkHttpClient httpClient = new OkHttpClient();
private static final Gson gson = new Gson(); private static final Gson gson = new Gson();
public static void setHttpClient(OkHttpClient httpClient) {
NameFetcher.httpClient = httpClient;
}
public static List<String> nameHistoryFromUuid(UUID uuid) throws IOException { public static List<String> nameHistoryFromUuid(UUID uuid) throws IOException {
String name = getName(uuid); String name = getName(uuid);
if (name == null) return Collections.emptyList(); if (name == null) return Collections.emptyList();

View File

@@ -12,7 +12,7 @@ package com.imaginarycode.minecraft.redisbungee.api.util.uuid;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.squareup.okhttp.*; import okhttp3.*;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -28,13 +28,7 @@ public class UUIDFetcher implements Callable<Map<String, UUID>> {
private final List<String> names; private final List<String> names;
private final boolean rateLimiting; private final boolean rateLimiting;
private static final Gson gson = new Gson(); private static final Gson gson = new Gson();
private static final OkHttpClient httpClient = new OkHttpClient();
public static void setHttpClient(OkHttpClient httpClient) {
UUIDFetcher.httpClient = httpClient;
}
private static OkHttpClient httpClient;
private UUIDFetcher(List<String> names, boolean rateLimiting) { private UUIDFetcher(List<String> names, boolean rateLimiting) {
this.names = ImmutableList.copyOf(names); this.names = ImmutableList.copyOf(names);

View File

@@ -61,7 +61,7 @@ public final class UUIDTranslator {
CachedUUIDEntry cachedUUIDEntry = nameToUuidMap.get(player.toLowerCase()); CachedUUIDEntry cachedUUIDEntry = nameToUuidMap.get(player.toLowerCase());
if (cachedUUIDEntry != null) { if (cachedUUIDEntry != null) {
if (!cachedUUIDEntry.expired()) if (!cachedUUIDEntry.expired())
return cachedUUIDEntry.getUuid(); return cachedUUIDEntry.uuid();
else else
nameToUuidMap.remove(player); nameToUuidMap.remove(player);
} }
@@ -93,11 +93,11 @@ public final class UUIDTranslator {
if (entry.expired()) { if (entry.expired()) {
unifiedJedis.hdel("uuid-cache", player.toLowerCase()); unifiedJedis.hdel("uuid-cache", player.toLowerCase());
// Doesn't hurt to also remove the UUID entry as well. // Doesn't hurt to also remove the UUID entry as well.
unifiedJedis.hdel("uuid-cache", entry.getUuid().toString()); unifiedJedis.hdel("uuid-cache", entry.uuid().toString());
} else { } else {
nameToUuidMap.put(player.toLowerCase(), entry); nameToUuidMap.put(player.toLowerCase(), entry);
uuidToNameMap.put(entry.getUuid(), entry); uuidToNameMap.put(entry.uuid(), entry);
return entry.getUuid(); return entry.uuid();
} }
} }
@@ -141,7 +141,7 @@ public final class UUIDTranslator {
CachedUUIDEntry cachedUUIDEntry = uuidToNameMap.get(player); CachedUUIDEntry cachedUUIDEntry = uuidToNameMap.get(player);
if (cachedUUIDEntry != null) { if (cachedUUIDEntry != null) {
if (!cachedUUIDEntry.expired()) if (!cachedUUIDEntry.expired())
return cachedUUIDEntry.getName(); return cachedUUIDEntry.name();
else else
uuidToNameMap.remove(player); uuidToNameMap.remove(player);
} }
@@ -159,11 +159,11 @@ public final class UUIDTranslator {
unifiedJedis.hdel("uuid-cache", player.toString()); unifiedJedis.hdel("uuid-cache", player.toString());
// Doesn't hurt to also remove the named entry as well. // Doesn't hurt to also remove the named entry as well.
// TODO: Since UUIDs are fixed, we could look up the name and see if the UUID matches. // TODO: Since UUIDs are fixed, we could look up the name and see if the UUID matches.
unifiedJedis.hdel("uuid-cache", entry.getName()); unifiedJedis.hdel("uuid-cache", entry.name());
} else { } else {
nameToUuidMap.put(entry.getName().toLowerCase(), entry); nameToUuidMap.put(entry.name().toLowerCase(), entry);
uuidToNameMap.put(player, entry); uuidToNameMap.put(player, entry);
return entry.getName(); return entry.name();
} }
} }

View File

@@ -50,6 +50,8 @@ useSSL: false
# An identifier for this network, which helps to separate redisbungee instances on same redis instance. # An identifier for this network, which helps to separate redisbungee instances on same redis instance.
# You can use environment variable 'REDISBUNGEE_NETWORK_ID' to override # You can use environment variable 'REDISBUNGEE_NETWORK_ID' to override
# Depending on the platform bungeecord or velocity system will append platform id to the network id
# to prevent proxies from different platforms from seeing each other. since 0.13.0
network-id: "main" network-id: "main"
# An identifier for this BungeeCord / Velocity instance. Will randomly generate if leaving it blank. # An identifier for this BungeeCord / Velocity instance. Will randomly generate if leaving it blank.
@@ -77,6 +79,13 @@ kick-when-online: true
# you can disable this when you want to handle motd yourself, use RedisBungee api to get total players when needed :) # you can disable this when you want to handle motd yourself, use RedisBungee api to get total players when needed :)
handle-motd: true handle-motd: true
# MOTD plugins compatibility setting
# Allowed values: FIRST, NORMAL, LAST
# This option enables RedisBungee to manage various interactions between other plugins and the online player count,
# which is dynamically updated to a global player count in ping responses if the handle-motd option is enabled.
# If you encounter issues with other plugins accessing or modifying the player count, try using a value of FIRST or LAST.
handle-motd-order: NORMAL
# A list of IP addresses for which RedisBungee will not modify the response for, useful for automatic # A list of IP addresses for which RedisBungee will not modify the response for, useful for automatic
# restart scripts. # restart scripts.
# Automatically disabled if handle-motd is disabled. # Automatically disabled if handle-motd is disabled.

View File

View File

@@ -3,8 +3,10 @@ plugins {
} }
dependencies { dependencies {
implementation(project(":RedisBungee-API")) compileOnly(project(":RedisBungee-API"))
implementation(libs.acf.core) implementation(libs.acf.core)
compileOnly(libs.adventure.api)
compileOnly(libs.adventure.miniMessage)
} }
description = "RedisBungee common commands" description = "RedisBungee common commands"

View File

@@ -10,14 +10,19 @@
package com.imaginarycode.minecraft.redisbungee.commands; package com.imaginarycode.minecraft.redisbungee.commands;
import co.aikar.commands.CommandContexts;
import co.aikar.commands.CommandManager; import co.aikar.commands.CommandManager;
import co.aikar.commands.InvalidCommandArgument;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.commands.legacy.LegacyRedisBungeeCommands; import com.imaginarycode.minecraft.redisbungee.commands.legacy.LegacyRedisBungeeCommands;
import java.util.UUID;
public class CommandLoader { public class CommandLoader {
public static void initCommands(CommandManager<?, ?, ?, ?, ?, ?> commandManager, RedisBungeePlugin<?> plugin) { public static void initCommands(CommandManager<?, ?, ?, ?, ?, ?> commandManager, RedisBungeePlugin<?> plugin) {
registerContexts(commandManager);
var commandsConfiguration = plugin.configuration().commandsConfiguration(); var commandsConfiguration = plugin.configuration().commandsConfiguration();
if (commandsConfiguration.redisbungeeEnabled()) { if (commandsConfiguration.redisbungeeEnabled()) {
commandManager.registerCommand(new CommandRedisBungee(plugin)); commandManager.registerCommand(new CommandRedisBungee(plugin));
@@ -26,6 +31,20 @@ public class CommandLoader {
commandManager.registerCommand(new LegacyRedisBungeeCommands(commandManager,plugin)); commandManager.registerCommand(new LegacyRedisBungeeCommands(commandManager,plugin));
} }
commandManager.registerCommand(new CommandRedisBungeeDebug(plugin));
}
private static void registerContexts(CommandManager<?, ?, ?, ?, ?, ?> commandManager) {
CommandContexts<?> commandContexts = commandManager.getCommandContexts();
commandContexts.registerContext(UUID.class, c -> {
String uuidString = c.popFirstArg();
try {
return UUID.fromString(uuidString);
} catch (IllegalArgumentException e) {
throw new InvalidCommandArgument("invaild uuid");
}
});
} }
} }

View File

@@ -0,0 +1,46 @@
/*
* 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.commands;
import co.aikar.commands.CommandIssuer;
import co.aikar.commands.annotation.*;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.commands.utils.AdventureBaseCommand;
import java.util.UUID;
@CommandAlias("rbd|redisbungeedebug")
@CommandPermission("redisbungee.command.debug.use")
@Description("debug commands")
public class CommandRedisBungeeDebug extends AdventureBaseCommand {
private final RedisBungeePlugin<?> plugin;
public CommandRedisBungeeDebug(RedisBungeePlugin<?> plugin) {
this.plugin = plugin;
}
@Subcommand("kickByName")
@Description("kicks a player from the network by name")
@Private
public void kick(CommandIssuer issuer, String playerName) {
plugin.playerDataManager().serializedPlayerKick(plugin.getUuidTranslator().getTranslatedUuid(playerName, false), "kicked using redisbungee api using name");
}
@Subcommand("kickByUUID")
@Description("kicks a player from the network by UUID")
@Private
public void kick(CommandIssuer issuer, UUID uuid) {
plugin.playerDataManager().serializedPlayerKick(uuid, "kicked using redisbungee api using uuid");
}
}

View File

@@ -19,7 +19,7 @@ import net.kyori.adventure.text.Component;
*/ */
public abstract class AdventureBaseCommand extends BaseCommand { public abstract class AdventureBaseCommand extends BaseCommand {
public static void sendMessage(CommandIssuer issuer, Component component) { protected void sendMessage(CommandIssuer issuer, Component component) {
CommandPlatformHelper.getPlatformHelper().sendMessage(issuer, component); CommandPlatformHelper.getPlatformHelper().sendMessage(issuer, component);
} }

View File

@@ -1,2 +1,2 @@
group=com.imaginarycode.minecraft group=com.imaginarycode.minecraft
version=0.12.1 version=0.13.0-SNAPSHOT

36
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,36 @@
[versions]
guava = "33.5.0-jre"
jedis = "5.2.0"
okhttp = "4.12.0"
configurateV3 = "3.7.3"
caffeine = "3.2.3"
adventure = "4.26.1"
adventure-bungeecord-platform = "4.4.1"
acf = "e2005dd62d"
bungeecordApi = "1.21-R0.5-SNAPSHOT"
velocity = "3.5.0-SNAPSHOT"
[plugins]
blossom = { id = "net.kyori.blossom", version = "2.2.0" }
indragit = {id = "net.kyori.indra.git", version="4.0.0"}
shadow = { id = "com.gradleup.shadow", version = "9.3.1" }
run-velocity = { id = "xyz.jpenilla.run-velocity", version = "2.3.1" }
[libraries]
guava = { module = "com.google.guava:guava", version.ref = "guava" }
jedis = { module = "redis.clients:jedis", version.ref = "jedis" }
okhttp = { module = "com.squareup.okhttp3:okhttp", version.ref = "okhttp" }
configurateV3 = { module = "org.spongepowered:configurate-yaml", version.ref = "configurateV3" }
caffeine = { module = "com.github.ben-manes.caffeine:caffeine", version.ref = "caffeine" }
adventure-api = { module = "net.kyori:adventure-api", version.ref = "adventure" }
adventure-miniMessage = { module = "net.kyori:adventure-text-minimessage", version.ref = "adventure" }
acf-core = { module = "com.github.ProxioDev.commands:acf-core", version.ref = "acf" }
acf-bungeecord = { module = "com.github.ProxioDev.commands:acf-bungee", version.ref = "acf" }
acf-velocity = { module = "com.github.ProxioDev.commands:acf-velocity", version.ref = "acf" }
platform-bungeecord = { module = "net.md-5:bungeecord-api", version.ref = "bungeecordApi" }
adventure-platforms-bungeecord = { module = "net.kyori:adventure-platform-bungeecord", version.ref = "adventure-bungeecord-platform" }
platform-velocity = { module = "com.velocitypowered:velocity-api", version.ref = "velocity" }

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

12
gradlew vendored
View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
# #
# SPDX-License-Identifier: Apache-2.0
#
############################################################################## ##############################################################################
# #
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop. # Darwin, MinGW, and NonStop.
# #
# (3) This script is generated from the Groovy template # (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project. # within the Gradle project.
# #
# You can find Gradle at https://github.com/gradle/gradle/. # You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034 # shellcheck disable=SC2034
APP_BASE_NAME=${0##*/} APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value. # Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum MAX_FD=maximum
@@ -112,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;; NONSTOP* ) nonstop=true ;;
esac esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM. # Determine the Java command to use to start the JVM.
@@ -203,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command: # Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped. # and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line. # treated as '${Hostname}' itself on the command line.
@@ -211,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \ set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \ "-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \ -classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \ -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@" "$@"
# Stop when "xargs" is not available. # Stop when "xargs" is not available.

26
gradlew.bat vendored
View File

@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off @if "%DEBUG%"=="" @echo off
@rem ########################################################################## @rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
@@ -57,22 +59,22 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. echo location of your Java installation. 1>&2
goto fail goto fail
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell

View File

@@ -1,2 +1,2 @@
jdk: jdk:
- openjdk17 - openjdk21

49
lang/build.gradle.kts Normal file
View File

@@ -0,0 +1,49 @@
plugins {
`java-library`
`maven-publish`
}
dependencies {
compileOnly(project(":RedisBungee-API"))
compileOnly(libs.adventure.api)
compileOnly(libs.adventure.miniMessage)
}
description = "RedisBungee languages"
java {
withJavadocJar()
withSourcesJar()
}
tasks {
// thanks again for paper too
withType<Javadoc> {
val options = options as StandardJavadocDocletOptions
options.use()
options.isDocFilesSubDirs = true
val adventureVersion = libs.adventure.api.get().version
options.links(
"https://jd.advntr.dev/api/$adventureVersion"
)
}
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(17)
}
javadoc {
options.encoding = Charsets.UTF_8.name()
}
processResources {
filteringCharset = Charsets.UTF_8.name()
}
}
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -8,10 +8,10 @@
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
*/ */
package com.imaginarycode.minecraft.redisbungee.api.config.loaders; package net.limework.valiobungee.config.lang;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.config.LangConfiguration; import com.imaginarycode.minecraft.redisbungee.api.config.loaders.GenericConfigLoader;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;
import ninja.leaping.configurate.ConfigurationNode; import ninja.leaping.configurate.ConfigurationNode;

View File

@@ -8,7 +8,7 @@
* http://www.eclipse.org/legal/epl-v10.html * http://www.eclipse.org/legal/epl-v10.html
*/ */
package com.imaginarycode.minecraft.redisbungee.api.config; package net.limework.valiobungee.config.lang;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage; import net.kyori.adventure.text.minimessage.MiniMessage;

View File

@@ -1,55 +1,30 @@
plugins { plugins {
`java-library` java
`maven-publish` alias(libs.plugins.shadow)
id("com.github.johnrengelman.shadow") version "8.1.1"
id("xyz.jpenilla.run-waterfall") version "2.0.0"
} }
dependencies { dependencies {
api(project(":RedisBungee-API")) implementation(project(":RedisBungee-Bungee"))
compileOnly(libs.platform.bungeecord) { 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.platforms.bungeecord)
implementation(libs.adventure.gson) implementation(libs.adventure.miniMessage)
implementation(libs.acf.bungeecord) implementation(libs.acf.bungeecord)
implementation(project(":RedisBungee-Commands")) implementation(project(":RedisBungee-Commands"))
implementation(project(":RedisBungee-Lang"))
} }
description = "RedisBungee Bungeecord implementation" description = "RedisBungee Bungeecord implementation"
java { java {
withJavadocJar()
withSourcesJar() withSourcesJar()
} }
tasks { 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 { compileJava {
options.encoding = Charsets.UTF_8.name() options.encoding = Charsets.UTF_8.name()
options.release.set(17) options.release.set(17)
} }
javadoc {
options.encoding = Charsets.UTF_8.name()
}
processResources { processResources {
filteringCharset = Charsets.UTF_8.name() filteringCharset = Charsets.UTF_8.name()
filesMatching("plugin.yml") { filesMatching("plugin.yml") {
@@ -63,7 +38,8 @@ tasks {
relocate("redis.clients.jedis", "com.imaginarycode.minecraft.redisbungee.internal.jedis") relocate("redis.clients.jedis", "com.imaginarycode.minecraft.redisbungee.internal.jedis")
relocate("redis.clients.util", "com.imaginarycode.minecraft.redisbungee.internal.jedisutil") relocate("redis.clients.util", "com.imaginarycode.minecraft.redisbungee.internal.jedisutil")
relocate("org.apache.commons.pool", "com.imaginarycode.minecraft.redisbungee.internal.commonspool") relocate("org.apache.commons.pool", "com.imaginarycode.minecraft.redisbungee.internal.commonspool")
relocate("com.squareup.okhttp", "com.imaginarycode.minecraft.redisbungee.internal.okhttp") relocate("okhttp3", "com.imaginarycode.minecraft.redisbungee.internal.okhttp3")
relocate("kotlin", "com.imaginarycode.minecraft.redisbungee.internal.kotlin")
relocate("okio", "com.imaginarycode.minecraft.redisbungee.internal.okio") relocate("okio", "com.imaginarycode.minecraft.redisbungee.internal.okio")
relocate("org.json", "com.imaginarycode.minecraft.redisbungee.internal.json") relocate("org.json", "com.imaginarycode.minecraft.redisbungee.internal.json")
// configurate shade // configurate shade
@@ -77,15 +53,9 @@ tasks {
relocate("com.github.benmanes.caffeine", "com.imaginarycode.minecraft.redisbungee.internal.caffeine") relocate("com.github.benmanes.caffeine", "com.imaginarycode.minecraft.redisbungee.internal.caffeine")
// acf shade // acf shade
relocate("co.aikar.commands", "com.imaginarycode.minecraft.redisbungee.internal.acf.commands") relocate("co.aikar.commands", "com.imaginarycode.minecraft.redisbungee.internal.acf.commands")
// adventure :/
relocate("net.kyori", "com.imaginarycode.minecraft.redisbungee.internal.net.kyori")
} }
} }
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -0,0 +1,47 @@
plugins {
`java-library`
`maven-publish`
}
dependencies {
api(project(":RedisBungee-API"))
compileOnly(libs.adventure.platforms.bungeecord)
compileOnly(libs.platform.bungeecord)
}
description = "RedisBungee Bungeecord API"
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://hub.spigotmc.org/jenkins/job/BungeeCord/ws/api/target/reports/apidocs", // bungeecord api
)
val apiDocs = File(rootProject.projectDir, "api/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,22 @@
/*
* 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.kyori.adventure.text.Component;
import java.util.UUID;
// this class used to redirect calls to keep the implementation and api separate
public interface ApiPlatformSupport {
void kickPlayer(UUID player, Component message);
}

View File

@@ -0,0 +1,163 @@
/*
* 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.kyori.adventure.text.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.chat.BaseComponent;
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.List;
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;
private static final BungeeComponentSerializer BUNGEE_COMPONENT_SERIALIZER = BungeeComponentSerializer.get();
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);
}
/**
* Kicks a player from the network
* calls {@link #getUuidFromName(String)} to get uuid
*
* @param playerName player name
* @param message kick message that player will see on kick
* @since 0.13.0
*/
public void kickPlayer(String playerName, BaseComponent[] message) {
kickPlayer(getUuidFromName(playerName), message);
}
/**
* Kicks a player from the network
*
* @param player player uuid
* @param message kick message that player will see on kick
* @since 0.13.0
*/
public void kickPlayer(UUID player, BaseComponent[] message) {
kickPlayer(player, BUNGEE_COMPONENT_SERIALIZER.deserialize(message));
}
/**
* Kicks a player from the network
* calls {@link #getUuidFromName(String)} to get uuid
*
* @param playerName player name
* @param message kick message that player will see on kick
* @since 0.12.0
*/
public void kickPlayer(String playerName, Component message) {
kickPlayer(getUuidFromName(playerName), message);
}
/**
* Kicks a player from the network
*
* @param player player uuid
* @param message kick message that player will see on kick
* @since 0.12.0
*/
public void kickPlayer(UUID player, Component message) {
((ApiPlatformSupport) this.plugin).kickPlayer(player, message);
}
/**
* Get the current BungeeCord / Velocity proxy ID for this server.
*
* @return the current server ID
* @see #getAllServers()
* @since 0.2.5
* @deprecated to avoid confusion between A server and A proxy see #getProxyId()
*/
@Deprecated(forRemoval = true)
public final String getServerId() {
return getProxyId();
}
/**
* Get all the linked proxies in this network.
*
* @return the list of all proxies
* @see #getServerId()
* @since 0.2.5
* @deprecated to avoid confusion between A server and A proxy see see {@link #getAllProxies()}
*/
@Deprecated(forRemoval = true)
public final List<String> getAllServers() {
return getAllProxies();
}
/**
* Register (a) PubSub channel(s), so that you may handle PubSubMessageEvent for it.
*
* @param channels the channels to register
* @since 0.3
* @deprecated No longer required
*/
@Deprecated(forRemoval = true)
public final void registerPubSubChannels(String... channels) {
}
/**
* Unregister (a) PubSub channel(s).
*
* @param channels the channels to unregister
* @since 0.3
* @deprecated No longer required
*/
@Deprecated(forRemoval = true)
public final void unregisterPubSubChannels(String... channels) {
}
/**
* Api instance
*
* @return the API instance.
* @since 0.6.5
*/
public static RedisBungeeAPI getRedisBungeeApi() {
return redisBungeeApi;
}
}

View File

@@ -13,10 +13,13 @@ package com.imaginarycode.minecraft.redisbungee;
import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager; import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent; 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.PlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent; import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.LoginEvent; import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent; import net.md_5.bungee.api.event.PlayerDisconnectEvent;
@@ -26,34 +29,38 @@ import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.api.plugin.Plugin; import net.md_5.bungee.api.plugin.Plugin;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class BungeePlayerDataManager extends PlayerDataManager<ProxiedPlayer, PostLoginEvent, PlayerDisconnectEvent, PubSubMessageEvent, PlayerChangedServerNetworkEvent, PlayerLeftNetworkEvent, ServerConnectedEvent> implements Listener { public class BungeePlayerDataManager extends PlayerDataManager<ProxiedPlayer> implements Listener {
public BungeePlayerDataManager(RedisBungeePlugin<ProxiedPlayer> plugin) { private final RedisBungee bPlugin;
public BungeePlayerDataManager(RedisBungee plugin) {
super(plugin); super(plugin);
bPlugin = plugin;
} }
@Override
@EventHandler @EventHandler
public void onPlayerChangedServerNetworkEvent(PlayerChangedServerNetworkEvent event) { public void onPlayerChangedServerNetworkEvent(PlayerChangedServerNetworkEvent event) {
super.handleNetworkPlayerServerChange(event); super.handleNetworkPlayerServerChange(event);
} }
@Override
@EventHandler @EventHandler
public void onNetworkPlayerQuit(PlayerLeftNetworkEvent event) { public void onNetworkPlayerQuit(PlayerLeftNetworkEvent event) {
super.handleNetworkPlayerQuit(event); super.handleNetworkPlayerQuit(event);
} }
@Override @EventHandler
public void onNetworkPlayerJoin(PlayerJoinedNetworkEvent event) {
super.handleNetworkPlayerJoin(event);
}
@EventHandler @EventHandler
public void onPubSubMessageEvent(PubSubMessageEvent event) { public void onPubSubMessageEvent(PubSubMessageEvent event) {
super.handlePubSubMessageEvent(event); super.handlePubSubMessageEvent(event);
} }
@Override
@EventHandler @EventHandler
public void onServerConnectedEvent(ServerConnectedEvent event) { public void onServerConnectedEvent(ServerConnectedEvent event) {
final String currentServer = event.getServer().getInfo().getName(); final String currentServer = event.getServer().getInfo().getName();
@@ -61,33 +68,63 @@ public class BungeePlayerDataManager extends PlayerDataManager<ProxiedPlayer, Po
super.playerChangedServer(event.getPlayer().getUniqueId(), oldServer, currentServer); super.playerChangedServer(event.getPlayer().getUniqueId(), oldServer, currentServer);
} }
private final BungeeComponentSerializer BUNGEE_COMPONENT_SERIALIZER = BungeeComponentSerializer.get();
private final static MiniMessage MINI_MESSAGE_SERIALIZER = MiniMessage.miniMessage();
@Override
public boolean handleSerializedKick(UUID uuid, String serializedMiniMessage) {
ProxiedPlayer player = plugin.getPlayer(uuid);
if (player == null) return false;
// decode the adventure component
if (serializedMiniMessage == null) {
// kick the player too even if the message is invalid
player.disconnect(BUNGEE_COMPONENT_SERIALIZER.serialize(Component.empty()));
plugin.logWarn("unable to decode serialized adventure component because its empty or null");
} else {
Component message = MINI_MESSAGE_SERIALIZER.deserialize(serializedMiniMessage);
player.disconnect(BUNGEE_COMPONENT_SERIALIZER.serialize(message));
}
return true;
}
public void kickPlayer(UUID player, Component message) {
serializedPlayerKick(player, MINI_MESSAGE_SERIALIZER.serialize(message));
}
@EventHandler @EventHandler
public void onLoginEvent(LoginEvent event) { public void onLoginEvent(LoginEvent event) {
event.registerIntent((Plugin) plugin); event.registerIntent((Plugin) plugin);
// check if online // check if online
if (getLastOnline(event.getConnection().getUniqueId()) == 0) { if (getLastOnline(event.getConnection().getUniqueId()) == 0) {
// because something can go wrong and proxy somehow does not update player data correctly on shutdown
// we have to check proxy if it has the player
String proxyId = getProxyFor(event.getConnection().getUniqueId());
if (proxyId == null || !plugin.proxyDataManager().isPlayerTrulyOnProxy(proxyId, event.getConnection().getUniqueId())) {
event.completeIntent((Plugin) plugin);
} else {
if (plugin.configuration().kickWhenOnline()) { if (plugin.configuration().kickWhenOnline()) {
kickPlayer(event.getConnection().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation()); kickPlayer(event.getConnection().getUniqueId(), bPlugin.langConfiguration().messages().loggedInFromOtherLocation());
// wait 3 seconds before releasing the event // wait 3 seconds before releasing the event
plugin.executeAsyncAfter(() -> event.completeIntent((Plugin) plugin), TimeUnit.SECONDS, 3); plugin.executeAsyncAfter(() -> event.completeIntent((Plugin) plugin), TimeUnit.SECONDS, 3);
} else { } else {
event.setCancelled(true); event.setCancelled(true);
event.setCancelReason(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().alreadyLoggedIn())); event.setCancelReason(BungeeComponentSerializer.get().serialize(bPlugin.langConfiguration().messages().alreadyLoggedIn()));
event.completeIntent((Plugin) plugin); event.completeIntent((Plugin) plugin);
} }
}
} else { } else {
event.completeIntent((Plugin) plugin); event.completeIntent((Plugin) plugin);
} }
} }
@Override
@EventHandler @EventHandler
public void onLoginEvent(PostLoginEvent event) { public void onLoginEvent(PostLoginEvent event) {
super.addPlayer(event.getPlayer().getUniqueId(), event.getPlayer().getName(), event.getPlayer().getAddress().getAddress()); super.addPlayer(event.getPlayer().getUniqueId(), event.getPlayer().getName(), event.getPlayer().getAddress().getAddress());
} }
@Override
@EventHandler @EventHandler
public void onDisconnectEvent(PlayerDisconnectEvent event) { public void onDisconnectEvent(PlayerDisconnectEvent event) {
super.removePlayer(event.getPlayer().getUniqueId()); super.removePlayer(event.getPlayer().getUniqueId());

View File

@@ -15,18 +15,15 @@ import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager;
import com.imaginarycode.minecraft.redisbungee.api.ProxyDataManager; import com.imaginarycode.minecraft.redisbungee.api.ProxyDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; 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.loaders.ConfigLoader;
import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration; 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.IPlayerChangedServerNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent; import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent; import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent; import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.summoners.JedisPooledSummoner;
import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner; import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner;
import com.imaginarycode.minecraft.redisbungee.api.util.InitialUtils; 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.api.util.uuid.UUIDTranslator;
import com.imaginarycode.minecraft.redisbungee.commands.CommandLoader; import com.imaginarycode.minecraft.redisbungee.commands.CommandLoader;
import com.imaginarycode.minecraft.redisbungee.commands.utils.CommandPlatformHelper; import com.imaginarycode.minecraft.redisbungee.commands.utils.CommandPlatformHelper;
@@ -34,10 +31,9 @@ import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetwork
import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent; import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PlayerLeftNetworkEvent; import com.imaginarycode.minecraft.redisbungee.events.PlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent; 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.Component;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.limework.valiobungee.config.lang.LangConfigLoader;
import net.limework.valiobungee.config.lang.LangConfiguration;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
import net.md_5.bungee.api.connection.ProxiedPlayer; import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Event; import net.md_5.bungee.api.plugin.Event;
@@ -50,8 +46,6 @@ import redis.clients.jedis.JedisPool;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.net.InetAddress; import java.net.InetAddress;
import java.sql.Date;
import java.time.Instant;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@@ -59,7 +53,7 @@ import java.util.concurrent.*;
import java.util.logging.Level; import java.util.logging.Level;
public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlayer>, ConfigLoader, LangConfigLoader { public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlayer>, ConfigLoader, LangConfigLoader, ApiPlatformSupport {
private static RedisBungeeAPI apiStatic; private static RedisBungeeAPI apiStatic;
private AbstractRedisBungeeAPI api; private AbstractRedisBungeeAPI api;
@@ -72,7 +66,6 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
private UUIDTranslator uuidTranslator; private UUIDTranslator uuidTranslator;
private RedisBungeeConfiguration configuration; private RedisBungeeConfiguration configuration;
private LangConfiguration langConfiguration; private LangConfiguration langConfiguration;
private OkHttpClient httpClient;
private BungeeCommandManager commandManager; private BungeeCommandManager commandManager;
private final Logger logger = LoggerFactory.getLogger("RedisBungee"); private final Logger logger = LoggerFactory.getLogger("RedisBungee");
@@ -83,7 +76,6 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
return this.configuration; return this.configuration;
} }
@Override
public LangConfiguration langConfiguration() { public LangConfiguration langConfiguration() {
return this.langConfiguration; return this.langConfiguration;
} }
@@ -99,7 +91,7 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
} }
@Override @Override
public PlayerDataManager<ProxiedPlayer, ?, ?, ?, ?, ?, ?> playerDataManager() { public PlayerDataManager<ProxiedPlayer> playerDataManager() {
return this.playerDataManager; return this.playerDataManager;
} }
@@ -168,15 +160,6 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
return this.getProxy().getPlayer(player).getName(); 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 @Override
public String getPlayerServerName(ProxiedPlayer player) { public String getPlayerServerName(ProxiedPlayer player) {
return player.getServer().getInfo().getName(); return player.getServer().getInfo().getName();
@@ -241,11 +224,6 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
// cleanup // cleanup
this.cleanupTask = getProxy().getScheduler().schedule(this, () -> this.proxyDataManager.correctionTask(), 0, 60, TimeUnit.SECONDS); this.cleanupTask = getProxy().getScheduler().schedule(this, () -> this.proxyDataManager.correctionTask(), 0, 60, TimeUnit.SECONDS);
// init the http lib // init the http lib
httpClient = new OkHttpClient();
Dispatcher dispatcher = new Dispatcher(getExecutorService());
httpClient.setDispatcher(dispatcher);
NameFetcher.setHttpClient(httpClient);
UUIDFetcher.setHttpClient(httpClient);
InitialUtils.checkRedisVersion(this); InitialUtils.checkRedisVersion(this);
uuidTranslator = new UUIDTranslator(this); uuidTranslator = new UUIDTranslator(this);
@@ -349,6 +327,21 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
this.summoner = summoner; this.summoner = summoner;
} }
@Override
public void onLangConfigLoad(LangConfiguration langConfiguration) {
this.langConfiguration = langConfiguration;
}
@Override
public String platformId() {
return "bungeecord";
}
@Override
public void kickPlayer(UUID player, Component message) {
this.playerDataManager.kickPlayer(player, message);
}
/** /**
* This returns an instance of {@link RedisBungeeAPI} * This returns an instance of {@link RedisBungeeAPI}
* *
@@ -362,12 +355,15 @@ public class RedisBungee extends Plugin implements RedisBungeePlugin<ProxiedPlay
@Deprecated @Deprecated
public JedisPool getPool() { public JedisPool getPool() {
return api.getJedisPool(); if (api.getMode() == RedisBungeeMode.SINGLE) {
JedisPool jedisPool = ((JedisPooledSummoner) getSummoner()).getCompatibilityJedisPool();
if (jedisPool == null) {
throw new IllegalStateException("JedisPool compatibility mode is disabled, Please enable it in the RedisBungee config.yml");
}
return jedisPool;
} else {
throw new IllegalStateException("Mode is not " + RedisBungeeMode.SINGLE);
}
} }
@Override
public void onLangConfigLoad(LangConfiguration langConfiguration) {
this.langConfiguration = langConfiguration;
}
} }

View File

@@ -17,7 +17,7 @@ import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import net.kyori.adventure.text.Component; import com.imaginarycode.minecraft.redisbungee.api.config.HandleMotdOrder;
import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
import net.md_5.bungee.api.AbstractReconnectHandler; import net.md_5.bungee.api.AbstractReconnectHandler;
import net.md_5.bungee.api.ProxyServer; import net.md_5.bungee.api.ProxyServer;
@@ -29,6 +29,7 @@ import net.md_5.bungee.api.event.ProxyPingEvent;
import net.md_5.bungee.api.event.ServerConnectEvent; import net.md_5.bungee.api.event.ServerConnectEvent;
import net.md_5.bungee.api.plugin.Listener; import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler; import net.md_5.bungee.event.EventHandler;
import net.md_5.bungee.event.EventPriority;
import java.util.*; import java.util.*;
@@ -36,14 +37,37 @@ import static com.imaginarycode.minecraft.redisbungee.api.util.serialize.MultiMa
public class RedisBungeeListener implements Listener { public class RedisBungeeListener implements Listener {
private final RedisBungeePlugin<ProxiedPlayer> plugin; private final RedisBungee plugin;
public RedisBungeeListener(RedisBungeePlugin<ProxiedPlayer> plugin) { public RedisBungeeListener(RedisBungee plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@EventHandler @EventHandler(priority = EventPriority.LOWEST)
public void onPing(ProxyPingEvent event) { public void onPingFirst(ProxyPingEvent event) {
if (plugin.configuration().handleMotdOrder() != HandleMotdOrder.FIRST) {
return;
}
onPing0(event);
}
@EventHandler(priority = EventPriority.NORMAL)
public void onPingNormal(ProxyPingEvent event) {
if (plugin.configuration().handleMotdOrder() != HandleMotdOrder.NORMAL) {
return;
}
onPing0(event);
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPingLast(ProxyPingEvent event) {
if (plugin.configuration().handleMotdOrder() != HandleMotdOrder.LAST) {
return;
}
onPing0(event);
}
private void onPing0(ProxyPingEvent event) {
if (!plugin.configuration().handleMotd()) return; if (!plugin.configuration().handleMotd()) return;
if (plugin.configuration().getExemptAddresses().contains(event.getConnection().getAddress().getAddress())) return; if (plugin.configuration().getExemptAddresses().contains(event.getConnection().getAddress().getAddress())) return;
ServerInfo forced = AbstractReconnectHandler.getForcedHost(event.getConnection()); ServerInfo forced = AbstractReconnectHandler.getForcedHost(event.getConnection());

View File

@@ -0,0 +1,49 @@
plugins {
java
alias(libs.plugins.shadow)
alias(libs.plugins.run.velocity)
}
dependencies {
implementation(project(":RedisBungee-Velocity"))
compileOnly(libs.platform.velocity)
annotationProcessor(libs.platform.velocity)
implementation(project(":RedisBungee-Commands"))
implementation(libs.acf.velocity)
implementation(project(":RedisBungee-Lang"))
}
description = "RedisBungee Velocity implementation"
java {
withSourcesJar()
}
tasks {
runVelocity {
velocityVersion(libs.versions.velocity.get())
environment["REDISBUNGEE_PROXY_ID"] = "velocity-1"
environment["REDISBUNGEE_NETWORK_ID"] = "dev"
}
compileJava {
options.encoding = Charsets.UTF_8.name()
options.release.set(21) // required by velocity
}
processResources {
filteringCharset = Charsets.UTF_8.name()
}
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("okhttp3", "com.imaginarycode.minecraft.redisbungee.internal.okhttp3")
relocate("kotlin", "com.imaginarycode.minecraft.redisbungee.internal.kotlin")
relocate("okio", "com.imaginarycode.minecraft.redisbungee.internal.okio")
relocate("org.json", "com.imaginarycode.minecraft.redisbungee.internal.json")
// acf shade
relocate("co.aikar.commands", "com.imaginarycode.minecraft.redisbungee.internal.acf.commands")
}
}

View File

@@ -17,6 +17,7 @@ import com.google.common.io.ByteArrayDataInput;
import com.google.common.io.ByteArrayDataOutput; import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams; import com.google.common.io.ByteStreams;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.config.HandleMotdOrder;
import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.connection.PluginMessageEvent; import com.velocitypowered.api.event.connection.PluginMessageEvent;
@@ -26,7 +27,6 @@ import com.velocitypowered.api.proxy.Player;
import com.velocitypowered.api.proxy.ServerConnection; import com.velocitypowered.api.proxy.ServerConnection;
import com.velocitypowered.api.proxy.server.RegisteredServer; import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.proxy.server.ServerPing; import com.velocitypowered.api.proxy.server.ServerPing;
import net.kyori.adventure.text.Component;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -36,14 +36,37 @@ import static com.imaginarycode.minecraft.redisbungee.api.util.serialize.MultiMa
public class RedisBungeeListener { public class RedisBungeeListener {
private final RedisBungeePlugin<Player> plugin; private final RedisBungeeVelocityPlugin plugin;
public RedisBungeeListener(RedisBungeePlugin<Player> plugin) { public RedisBungeeListener(RedisBungeeVelocityPlugin plugin) {
this.plugin = plugin; this.plugin = plugin;
} }
@Subscribe(order = PostOrder.LAST) // some plugins changes it online players so we need to be executed as last @Subscribe(order = PostOrder.FIRST)
public void onPing(ProxyPingEvent event) { public void onPingFirst(ProxyPingEvent event) {
if (plugin.configuration().handleMotdOrder() != HandleMotdOrder.FIRST) {
return;
}
onPing0(event);
}
@Subscribe(order = PostOrder.NORMAL)
public void onPingNormal(ProxyPingEvent event) {
if (plugin.configuration().handleMotdOrder() != HandleMotdOrder.NORMAL) {
return;
}
onPing0(event);
}
@Subscribe(order = PostOrder.LAST)
public void onPingLast(ProxyPingEvent event) {
if (plugin.configuration().handleMotdOrder() != HandleMotdOrder.LAST) {
return;
}
onPing0(event);
}
private void onPing0(ProxyPingEvent event) {
if (!plugin.configuration().handleMotd()) return; if (!plugin.configuration().handleMotd()) return;
if (plugin.configuration().getExemptAddresses().contains(event.getConnection().getRemoteAddress().getAddress())) return; if (plugin.configuration().getExemptAddresses().contains(event.getConnection().getRemoteAddress().getAddress())) return;
@@ -146,8 +169,11 @@ public class RedisBungeeListener {
return; return;
} }
} }
try {
// ServerConnection throws IllegalStateException when connection dies somehow so just ignore :/
((ServerConnection) event.getSource()).sendPluginMessage(event.getIdentifier(), out.toByteArray()); ((ServerConnection) event.getSource()).sendPluginMessage(event.getIdentifier(), out.toByteArray());
} catch (IllegalStateException ignored) {
}
}); });
} }

View File

@@ -18,25 +18,19 @@ import com.imaginarycode.minecraft.redisbungee.api.RedisBungeeMode;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin; import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.commands.CommandLoader; import com.imaginarycode.minecraft.redisbungee.commands.CommandLoader;
import com.imaginarycode.minecraft.redisbungee.commands.utils.CommandPlatformHelper; import com.imaginarycode.minecraft.redisbungee.commands.utils.CommandPlatformHelper;
import com.imaginarycode.minecraft.redisbungee.api.config.LangConfiguration;
import com.imaginarycode.minecraft.redisbungee.api.config.loaders.ConfigLoader; import com.imaginarycode.minecraft.redisbungee.api.config.loaders.ConfigLoader;
import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration; 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.IPlayerChangedServerNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent; import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerJoinedNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent; import com.imaginarycode.minecraft.redisbungee.api.events.IPlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent; import com.imaginarycode.minecraft.redisbungee.api.events.IPubSubMessageEvent;
import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner; import com.imaginarycode.minecraft.redisbungee.api.summoners.Summoner;
import com.imaginarycode.minecraft.redisbungee.api.util.InitialUtils; 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.api.util.uuid.UUIDTranslator;
import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent; import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent; import com.imaginarycode.minecraft.redisbungee.events.PlayerJoinedNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PlayerLeftNetworkEvent; import com.imaginarycode.minecraft.redisbungee.events.PlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent; import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import com.squareup.okhttp.Dispatcher;
import com.squareup.okhttp.OkHttpClient;
import com.velocitypowered.api.event.PostOrder; import com.velocitypowered.api.event.PostOrder;
import com.velocitypowered.api.event.Subscribe; import com.velocitypowered.api.event.Subscribe;
import com.velocitypowered.api.event.proxy.ProxyInitializeEvent; import com.velocitypowered.api.event.proxy.ProxyInitializeEvent;
@@ -50,6 +44,8 @@ import com.velocitypowered.api.proxy.messages.LegacyChannelIdentifier;
import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier; import com.velocitypowered.api.proxy.messages.MinecraftChannelIdentifier;
import com.velocitypowered.api.scheduler.ScheduledTask; import com.velocitypowered.api.scheduler.ScheduledTask;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.limework.valiobungee.config.lang.LangConfiguration;
import net.limework.valiobungee.config.lang.LangConfigLoader;
import org.slf4j.Logger; import org.slf4j.Logger;
import redis.clients.jedis.exceptions.JedisConnectionException; import redis.clients.jedis.exceptions.JedisConnectionException;
@@ -57,18 +53,15 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.net.InetAddress; import java.net.InetAddress;
import java.nio.file.Path; import java.nio.file.Path;
import java.sql.Date;
import java.time.Duration; import java.time.Duration;
import java.time.Instant;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Plugin(id = "redisbungee", name = "RedisBungee", version = Constants.VERSION, url = "https://github.com/ProxioDev/RedisBungee", authors = {"astei", "ProxioDev"}) @Plugin(id = "redisbungee", name = "RedisBungee", version = Constants.VERSION, url = "https://github.com/ProxioDev/RedisBungee", authors = {"astei", "ProxioDev"})
public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, ConfigLoader, LangConfigLoader { public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, ConfigLoader, LangConfigLoader, ApiPlatformSupport {
private final ProxyServer server; private final ProxyServer server;
private final Logger logger; private final Logger logger;
private final Path dataFolder; private final Path dataFolder;
@@ -78,7 +71,6 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
private final UUIDTranslator uuidTranslator; private final UUIDTranslator uuidTranslator;
private RedisBungeeConfiguration configuration; private RedisBungeeConfiguration configuration;
private LangConfiguration langConfiguration; private LangConfiguration langConfiguration;
private final OkHttpClient httpClient;
private final ProxyDataManager proxyDataManager; private final ProxyDataManager proxyDataManager;
@@ -127,11 +119,6 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
}; };
this.playerDataManager = new VelocityPlayerDataManager(this); this.playerDataManager = new VelocityPlayerDataManager(this);
uuidTranslator = new UUIDTranslator(this); uuidTranslator = new UUIDTranslator(this);
this.httpClient = new OkHttpClient();
Dispatcher dispatcher = new Dispatcher(Executors.newFixedThreadPool(6));
this.httpClient.setDispatcher(dispatcher);
NameFetcher.setHttpClient(httpClient);
UUIDFetcher.setHttpClient(httpClient);
} }
@@ -151,7 +138,7 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
} }
@Override @Override
public PlayerDataManager<Player, ?, ?, ?, ?, ?, ?> playerDataManager() { public PlayerDataManager<Player> playerDataManager() {
return this.playerDataManager; return this.playerDataManager;
} }
@@ -216,7 +203,6 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
return this.configuration; return this.configuration;
} }
@Override
public LangConfiguration langConfiguration() { public LangConfiguration langConfiguration() {
return this.langConfiguration; return this.langConfiguration;
} }
@@ -241,15 +227,6 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
return this.getProxy().getPlayer(player).map(Player::getUsername).orElse(null); return this.getProxy().getPlayer(player).map(Player::getUsername).orElse(null);
} }
@Override
public boolean handlePlatformKick(UUID uuid, Component message) {
Player player = getPlayer(uuid);
if (player == null) return false;
player.disconnect(message);
return true;
}
@Override @Override
public String getPlayerServerName(Player player) { public String getPlayerServerName(Player player) {
return player.getCurrentServer().map(serverConnection -> serverConnection.getServerInfo().getName()).orElse(null); return player.getCurrentServer().map(serverConnection -> serverConnection.getServerInfo().getName()).orElse(null);
@@ -300,8 +277,6 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
if (heartbeatTask != null) { if (heartbeatTask != null) {
heartbeatTask.cancel(); heartbeatTask.cancel();
} }
try { try {
this.proxyDataManager.close(); this.proxyDataManager.close();
this.jedisSummoner.close(); this.jedisSummoner.close();
@@ -309,13 +284,6 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
throw new RuntimeException(e); throw new RuntimeException(e);
} }
this.httpClient.getDispatcher().getExecutorService().shutdown();
try {
logInfo("waiting for httpclient thread-pool termination.....");
this.httpClient.getDispatcher().getExecutorService().awaitTermination(20, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (commandManager != null) commandManager.unregisterCommands(); if (commandManager != null) commandManager.unregisterCommands();
logInfo("RedisBungee shutdown complete"); logInfo("RedisBungee shutdown complete");
} }
@@ -373,6 +341,11 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
return server; return server;
} }
@Override
public void kickPlayer(UUID player, Component message) {
this.playerDataManager.kickPlayer(player, message);
}
public Logger getLogger() { public Logger getLogger() {
return logger; return logger;
} }
@@ -384,4 +357,9 @@ public class RedisBungeeVelocityPlugin implements RedisBungeePlugin<Player>, Con
public InputStream getResourceAsStream(String name) { public InputStream getResourceAsStream(String name) {
return this.getClass().getClassLoader().getResourceAsStream(name); return this.getClass().getClassLoader().getResourceAsStream(name);
} }
@Override
public String platformId() {
return "velocity";
}
} }

View File

@@ -11,9 +11,8 @@
package com.imaginarycode.minecraft.redisbungee; package com.imaginarycode.minecraft.redisbungee;
import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager; import com.imaginarycode.minecraft.redisbungee.api.PlayerDataManager;
import com.imaginarycode.minecraft.redisbungee.api.RedisBungeePlugin;
import com.imaginarycode.minecraft.redisbungee.api.config.RedisBungeeConfiguration;
import com.imaginarycode.minecraft.redisbungee.events.PlayerChangedServerNetworkEvent; 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.PlayerLeftNetworkEvent;
import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent; import com.imaginarycode.minecraft.redisbungee.events.PubSubMessageEvent;
import com.velocitypowered.api.event.Continuation; import com.velocitypowered.api.event.Continuation;
@@ -25,33 +24,41 @@ import com.velocitypowered.api.event.connection.PostLoginEvent;
import com.velocitypowered.api.event.player.ServerConnectedEvent; import com.velocitypowered.api.event.player.ServerConnectedEvent;
import com.velocitypowered.api.proxy.Player; import com.velocitypowered.api.proxy.Player;
import net.kyori.adventure.text.Component; import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.minimessage.MiniMessage;
import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer;
import java.util.UUID;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
public class VelocityPlayerDataManager extends PlayerDataManager<Player, PostLoginEvent, DisconnectEvent, PubSubMessageEvent, PlayerChangedServerNetworkEvent, PlayerLeftNetworkEvent, ServerConnectedEvent> { public class VelocityPlayerDataManager extends PlayerDataManager<Player> {
public VelocityPlayerDataManager(RedisBungeePlugin<Player> plugin) {
private final RedisBungeeVelocityPlugin vplugin;
public VelocityPlayerDataManager(RedisBungeeVelocityPlugin plugin) {
super(plugin); super(plugin);
this.vplugin = plugin;
} }
@Override
@Subscribe @Subscribe
public void onPlayerChangedServerNetworkEvent(PlayerChangedServerNetworkEvent event) { public void onPlayerChangedServerNetworkEvent(PlayerChangedServerNetworkEvent event) {
handleNetworkPlayerServerChange(event); handleNetworkPlayerServerChange(event);
} }
@Override
@Subscribe @Subscribe
public void onNetworkPlayerQuit(PlayerLeftNetworkEvent event) { public void onNetworkPlayerQuit(PlayerLeftNetworkEvent event) {
handleNetworkPlayerQuit(event); handleNetworkPlayerQuit(event);
} }
@Override @Subscribe
public void onNetworkPlayerJoin(PlayerJoinedNetworkEvent event) {
handleNetworkPlayerJoin(event);
}
@Subscribe @Subscribe
public void onPubSubMessageEvent(PubSubMessageEvent event) { public void onPubSubMessageEvent(PubSubMessageEvent event) {
handlePubSubMessageEvent(event); handlePubSubMessageEvent(event);
} }
@Override
@Subscribe @Subscribe
public void onServerConnectedEvent(ServerConnectedEvent event) { public void onServerConnectedEvent(ServerConnectedEvent event) {
final String currentServer = event.getServer().getServerInfo().getName(); final String currentServer = event.getServer().getServerInfo().getName();
@@ -64,30 +71,56 @@ public class VelocityPlayerDataManager extends PlayerDataManager<Player, PostLog
super.playerChangedServer(event.getPlayer().getUniqueId(), oldServer, currentServer); super.playerChangedServer(event.getPlayer().getUniqueId(), oldServer, currentServer);
} }
private final static MiniMessage MINI_MESSAGE_SERIALIZER = MiniMessage.miniMessage();
@Override
public boolean handleSerializedKick(UUID uuid, String serializedMiniMessage) {
Player player = plugin.getPlayer(uuid);
if (player == null) return false;
// decode the adventure component
if (serializedMiniMessage == null) {
// kick the player too even if the message is invalid
player.disconnect(Component.empty());
plugin.logWarn("unable to decode serialized adventure component because its empty or null");
} else {
Component message = MINI_MESSAGE_SERIALIZER.deserialize(serializedMiniMessage);
player.disconnect(message);
}
return true;
}
public void kickPlayer(UUID player, Component message) {
serializedPlayerKick(player, MINI_MESSAGE_SERIALIZER.serialize(message));
}
@Subscribe @Subscribe
public void onLoginEvent(LoginEvent event, Continuation continuation) { public void onLoginEvent(LoginEvent event, Continuation continuation) {
// check if online // check if online
if (getLastOnline(event.getPlayer().getUniqueId()) == 0) { if (getLastOnline(event.getPlayer().getUniqueId()) == 0) {
// because something can go wrong and proxy somehow does not update player data correctly on shutdown
// we have to check proxy if it has the player
String proxyId = getProxyFor(event.getPlayer().getUniqueId());
if (proxyId == null || !plugin.proxyDataManager().isPlayerTrulyOnProxy(proxyId, event.getPlayer().getUniqueId())) {
continuation.resume();
} else {
if (plugin.configuration().kickWhenOnline()) { if (plugin.configuration().kickWhenOnline()) {
kickPlayer(event.getPlayer().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation()); kickPlayer(event.getPlayer().getUniqueId(), vplugin.langConfiguration().messages().loggedInFromOtherLocation());
// wait 3 seconds before releasing the event // wait 3 seconds before releasing the event
plugin.executeAsyncAfter(continuation::resume, TimeUnit.SECONDS, 3); plugin.executeAsyncAfter(continuation::resume, TimeUnit.SECONDS, 3);
} else { } else {
event.setResult(ResultedEvent.ComponentResult.denied(plugin.langConfiguration().messages().alreadyLoggedIn())); event.setResult(ResultedEvent.ComponentResult.denied(vplugin.langConfiguration().messages().alreadyLoggedIn()));
continuation.resume(); continuation.resume();
} }
}
} else { } else {
continuation.resume(); continuation.resume();
} }
} }
@Override
@Subscribe @Subscribe
public void onLoginEvent(PostLoginEvent event) { public void onLoginEvent(PostLoginEvent event) {
addPlayer(event.getPlayer().getUniqueId(), event.getPlayer().getUsername(), event.getPlayer().getRemoteAddress().getAddress()); addPlayer(event.getPlayer().getUniqueId(), event.getPlayer().getUsername(), event.getPlayer().getRemoteAddress().getAddress());
} }
@Override
@Subscribe @Subscribe
public void onDisconnectEvent(DisconnectEvent event) { public void onDisconnectEvent(DisconnectEvent event) {
if (event.getLoginStatus() == DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN || event.getLoginStatus() == DisconnectEvent.LoginStatus.PRE_SERVER_JOIN) { if (event.getLoginStatus() == DisconnectEvent.LoginStatus.SUCCESSFUL_LOGIN || event.getLoginStatus() == DisconnectEvent.LoginStatus.PRE_SERVER_JOIN) {

View File

@@ -0,0 +1,56 @@
plugins {
`java-library`
`maven-publish`
}
dependencies {
api(project(":RedisBungee-API")) {
// Since velocity already includes guava / configurate / guava exlude them
exclude("com.google.guava", "guava")
exclude("com.google.code.gson", "gson")
exclude("org.spongepowered", "configurate-yaml")
exclude("com.github.ben-manes.caffeine", "caffeine")
}
implementation(project(":RedisBungee-Lang"))
compileOnly(libs.platform.velocity)
}
description = "RedisBungee Velocity API"
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://jd.papermc.io/velocity/3.0.0/", // velocity api
)
val apiDocs = File(rootProject.projectDir, "api/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(21) // required by velocity
}
javadoc {
options.encoding = Charsets.UTF_8.name()
}
processResources {
filteringCharset = Charsets.UTF_8.name()
}
}
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -0,0 +1,25 @@
/*
* 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.velocitypowered.api.proxy.ProxyServer;
import net.kyori.adventure.text.Component;
import java.util.UUID;
// this class used to redirect calls to keep the implementation and api separate
public interface ApiPlatformSupport {
ProxyServer getProxy();
void kickPlayer(UUID player, Component message);
}

Some files were not shown because too many files have changed in this diff Show More