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

39 Commits

Author SHA1 Message Date
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
8a6d97e923 bump to 0.12.1 2024-04-28 23:33:07 +04:00
a65b1cdf5c fix: adventure api version was replaced by guava 2024-04-28 23:32:08 +04:00
25441a5122 update .github/workflow/gradle.yml branch name 2024-04-28 23:18:01 +04:00
b9c7c31c09 oops: forgot to cache uuids/name of joined player 2024-04-28 23:16:19 +04:00
27358d2f5f change big uuid cache message to include the '/rb clean' 2024-04-28 23:16:18 +04:00
c736f39e7f bump version to 0.12.1-snapshot 2024-04-28 23:16:18 +04:00
7b90a34fae Update README.md 2024-04-28 20:36:09 +04:00
1593c2d628 0.12.0 (#86)
## NOTES
data system shouldn't effect anybody, unless you do any direct query to
Redis query data, you should adapt the changes, by viewing classes
`ProxyDataManager` and `PlayerDataManager`

# Changes 
* RedisBungee is compiled with `java 17` now, Due java 11 support is
ending at end of September
* config version is now `2` which will reset your config if older
version
* Adventure API is included inside RedisBungee API
* new Language infrastructure for RedisBungee built-in messages #85
*commands not included yet*
* New data system which replaces Redis PubSub with Redis Streams *see
below*
* Ability to connect player to last server they where on using an config
option #84
* new environment variable `REDISBUNGEE_PROXY_ID` which can be set
before launch
* new environment variable `REDISBUNGEE_NETWORK_ID` which can be set
before launch
* RedisBungee requires redis version 6.2 or above  #88 
* Better command system
https://github.com/ProxioDev/RedisBungee/issues/93

## New data system
Due limitation of Redis PubSub in Cluster environment, Internals of
RedisBungee were changed to support Redis Streams
- Network Ids
  - networks ids used to group network proxies
    - example having 'test' network and 'main' network
- Networks in the same redis server / cluster share the same UUID cache
- Heartbeat system:
- RedisBungee old heartbeat system used hastset on redisbungee to store
the current unix time of the proxy to check what every proxy died or
not, now instead we publish the heartbeat using unix time, and online
count to proxy which proxy store it in their memory, which allow the
`get number of online players` to be faster than pooling whole list in
old data system.

- PubSub
- since redisbungee was initially designed with pubsub in mind,
registration no longer required now for event to fire, see the api
changes below.

## Commands System
* rewritten using [acf lib](https://github.com/aikar/commands) to be
platform independent
* new command `/rb` or `/redisbungee` with sub commands `help`, `info`,
'clean', 'show'.

* 'rb'
  * '/rb' and '/rb info'

![image](https://github.com/ProxioDev/RedisBungee/assets/34905970/70796ab0-b5fd-4578-8c93-c976e517df95)

  * '/rb show'
  

![image](https://github.com/ProxioDev/RedisBungee/assets/34905970/56332c37-701f-43e0-946b-6894b845fab3)

* configuration to disable or override each command from legacy to new
introduced one `/rb`
```yaml

# For redis bungee legacy commands
# either can be run using '/rbl glist' for example
# or if 'install' is set to true '/glist' can be used.
# 'install' also overrides the proxy installed commands
#
# In legacy commands each command got it own permissions since they had it own permission pre new command system,
# so it's also applied to subcommands in '/rbl'.
commands:
  # Permission redisbungee.legacy.use
  redisbungee-legacy:
    enabled: false
    subcommands:
        # Permission redisbungee.command.glist
        glist:
          enabled: false
          install: false
        # Permission redisbungee.command.find
        find:
          enabled: false
          install: false
        # Permission redisbungee.command.lastseen
        lastseen:
          enabled: false
          install: false
        # Permission redisbungee.command.ip
        ip:
          enabled: false
          install: false
        # Permission redisbungee.command.pproxy
        pproxy:
          enabled: false
          install: false
        # Permission redisbungee.command.sendtoall
        sendtoall:
          enabled: false
          install: false
        # Permission redisbungee.command.serverid
        serverid:
          enabled: false
          install: false
        # Permission redisbungee.command.serverids
        serverids:
          enabled: false
          install: false
       # Permission redisbungee.command.plist
        plist:
          enabled: false
          install: false
  # Permission redisbungee.command.use
  redisbungee:
    enabled: true
```

## API changes
- Kick api Deprecated: 
  - `kickPlayer(String playerName, String message) `
  - `kickPlayer(UUID playerUUID, String message) `

- newer where added using adventure api:
  - `kickPlayer(String playerName, Component message) `
  - `kickPlayer(UUID playerUUID, Component message) `

-  PubSub registration api Deprecated:
```java
/**
     * 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) {
    }

```
# Contributors

* `summoncraft.us` for running this branch in production
* @SrBedrock for providing [Brazilian
Portuguese](https://en.wikipedia.org/wiki/Brazilian_Portuguese)
translation #87
 
# issues
closes #84 
closes #88 
closes #92 
closes #81
closes #93

---------

Signed-off-by: mohammed jasem alaajel <xrambad@gmail.com>
Co-authored-by: ThiagoROX <51332006+SrBedrock@users.noreply.github.com>
2024-04-28 15:29:53 +04:00
97 changed files with 282 additions and 162 deletions

View File

@@ -5,9 +5,9 @@ name: RedisBungee Build
on: on:
push: push:
branches: [ develop ] branches: [ stable, develop ]
pull_request: pull_request:
branches: [ develop ] branches: [ stable, develop ]
jobs: jobs:
build: build:
@@ -24,19 +24,19 @@ jobs:
- 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

@@ -9,6 +9,10 @@ or [Velocity*](https://github.com/PaperMC/Velocity) proxies
[![](https://raw.githubusercontent.com/Prospector/badges/master/modrinth-badge-72h-padded.png)](https://modrinth.com/plugin/redisbungee) [![](https://raw.githubusercontent.com/Prospector/badges/master/modrinth-badge-72h-padded.png)](https://modrinth.com/plugin/redisbungee)
## Wiki
https://github.com/ProxioDev/RedisBungee/wiki
## Support ## Support
open an issue with question button open an issue with question button

View File

@@ -52,7 +52,7 @@ tasks {
val jedisVersion = libs.jedis.get().version val jedisVersion = libs.jedis.get().version
val configurateVersion = libs.configurate.get().version val configurateVersion = libs.configurate.get().version
val guavaVersion = libs.guava.get().version val guavaVersion = libs.guava.get().version
val adventureVersion = libs.guava.get().version val adventureVersion = libs.adventure.plain.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

@@ -224,7 +224,7 @@ public abstract class AbstractRedisBungeeAPI {
* @since 0.2.5 * @since 0.2.5
* @deprecated to avoid confusion between A server and A proxy see #getProxyId() * @deprecated to avoid confusion between A server and A proxy see #getProxyId()
*/ */
@Deprecated @Deprecated(forRemoval = true)
public final String getServerId() { public final String getServerId() {
return getProxyId(); return getProxyId();
} }
@@ -248,7 +248,7 @@ public abstract class AbstractRedisBungeeAPI {
* @since 0.2.5 * @since 0.2.5
* @deprecated to avoid confusion between A server and A proxy see see {@link #getAllProxies()} * @deprecated to avoid confusion between A server and A proxy see see {@link #getAllProxies()}
*/ */
@Deprecated @Deprecated(forRemoval = true)
public final List<String> getAllServers() { public final List<String> getAllServers() {
return getAllProxies(); return getAllProxies();
} }
@@ -260,7 +260,7 @@ public abstract class AbstractRedisBungeeAPI {
* @since 0.3 * @since 0.3
* @deprecated No longer required * @deprecated No longer required
*/ */
@Deprecated @Deprecated(forRemoval = true)
public final void registerPubSubChannels(String... channels) { public final void registerPubSubChannels(String... channels) {
} }
@@ -271,7 +271,7 @@ public abstract class AbstractRedisBungeeAPI {
* @since 0.3 * @since 0.3
* @deprecated No longer required * @deprecated No longer required
*/ */
@Deprecated @Deprecated(forRemoval = true)
public final void unregisterPubSubChannels(String... channels) { public final void unregisterPubSubChannels(String... channels) {
} }
@@ -352,7 +352,7 @@ public abstract class AbstractRedisBungeeAPI {
* @since 0.8.0 * @since 0.8.0
* @deprecated * @deprecated
*/ */
@Deprecated @Deprecated(forRemoval = true)
public void kickPlayer(String playerName, String message) { public void kickPlayer(String playerName, String message) {
kickPlayer(getUuidFromName(playerName), message); kickPlayer(getUuidFromName(playerName), message);
} }
@@ -365,7 +365,7 @@ public abstract class AbstractRedisBungeeAPI {
* @since 0.8.0 * @since 0.8.0
* @deprecated * @deprecated
*/ */
@Deprecated @Deprecated(forRemoval = true)
public void kickPlayer(UUID playerUUID, String message) { public void kickPlayer(UUID playerUUID, String message) {
kickPlayer(playerUUID, Component.text(message)); kickPlayer(playerUUID, Component.text(message));
} }
@@ -402,7 +402,9 @@ public abstract class AbstractRedisBungeeAPI {
* @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#SINGLE} * @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#SINGLE}
* @see #getJedisPool() * @see #getJedisPool()
* @since 0.7.0 * @since 0.7.0
* @deprecated use {@link #getSummoner() }
*/ */
@Deprecated(forRemoval = true)
public Jedis requestJedis() { public Jedis requestJedis() {
if (getMode() == RedisBungeeMode.SINGLE) { if (getMode() == RedisBungeeMode.SINGLE) {
return getJedisPool().getResource(); return getJedisPool().getResource();
@@ -423,7 +425,7 @@ public abstract class AbstractRedisBungeeAPI {
if (getMode() == RedisBungeeMode.SINGLE) { if (getMode() == RedisBungeeMode.SINGLE) {
JedisPool jedisPool = ((JedisPooledSummoner) this.plugin.getSummoner()).getCompatibilityJedisPool(); JedisPool jedisPool = ((JedisPooledSummoner) this.plugin.getSummoner()).getCompatibilityJedisPool();
if (jedisPool == null) { if (jedisPool == null) {
throw new IllegalStateException("JedisPool compatibility mode is disabled"); throw new IllegalStateException("JedisPool compatibility mode is disabled, Please enable it in the RedisBungee config.yml");
} }
return jedisPool; return jedisPool;
} else { } else {
@@ -438,7 +440,9 @@ public abstract class AbstractRedisBungeeAPI {
* @return {@link redis.clients.jedis.JedisCluster} * @return {@link redis.clients.jedis.JedisCluster}
* @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#CLUSTER} * @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#CLUSTER}
* @since 0.8.0 * @since 0.8.0
* @deprecated use {@link #getSummoner()}
*/ */
@Deprecated(forRemoval = true)
public JedisCluster requestClusterJedis() { public JedisCluster requestClusterJedis() {
if (getMode() == RedisBungeeMode.CLUSTER) { if (getMode() == RedisBungeeMode.CLUSTER) {
return ((JedisClusterSummoner) this.plugin.getSummoner()).obtainResource(); return ((JedisClusterSummoner) this.plugin.getSummoner()).obtainResource();
@@ -454,7 +458,9 @@ public abstract class AbstractRedisBungeeAPI {
* @return {@link redis.clients.jedis.JedisPooled} * @return {@link redis.clients.jedis.JedisPooled}
* @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#SINGLE} * @throws IllegalStateException if the {@link #getMode()} is not equal to {@link RedisBungeeMode#SINGLE}
* @since 0.8.0 * @since 0.8.0
* @deprecated use {@link #getSummoner()}
*/ */
@Deprecated(forRemoval = true)
public JedisPooled requestJedisPooled() { public JedisPooled requestJedisPooled() {
if (getMode() == RedisBungeeMode.SINGLE) { if (getMode() == RedisBungeeMode.SINGLE) {
return ((JedisPooledSummoner) this.plugin.getSummoner()).obtainResource(); return ((JedisPooledSummoner) this.plugin.getSummoner()).obtainResource();

View File

@@ -28,25 +28,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, LE, DE, PS extends IPubSubMessageEvent, SC extends IPlayerChangedServerNetworkEvent, NJE extends IPlayerLeftNetworkEvent, CE> {
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 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 JSONComponentSerializer COMPONENT_SERIALIZER = JSONComponentSerializer.json();
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,30 +54,34 @@ 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); //l public abstract void onPlayerChangedServerNetworkEvent(SC event);
public abstract void onNetworkPlayerQuit(NJE event); // public abstract void onNetworkPlayerQuit(NJE event);
// local events // local events
public abstract void onPubSubMessageEvent(PS event); //public abstract void onPubSubMessageEvent(PS event);
public abstract void onServerConnectedEvent(CE event); //public abstract void onServerConnectedEvent(CE event);
public abstract void onLoginEvent(LE event); //public abstract void onLoginEvent(LE event);
public abstract void onDisconnectEvent(DE event);
//public abstract void onDisconnectEvent(DE event);
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) {
this.proxyCache.invalidate(event.getUuid()); this.proxyCache.invalidate(event.getUuid());
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());
//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) {
@@ -142,8 +143,6 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
handleServerChangeRedis(uuid, to); handleServerChangeRedis(uuid, to);
} }
private final JSONComponentSerializer COMPONENT_SERIALIZER =JSONComponentSerializer.json();
public void kickPlayer(UUID uuid, Component message) { public void kickPlayer(UUID uuid, Component message) {
if (!plugin.handlePlatformKick(uuid, message)) { // handle locally before SENDING a message if (!plugin.handlePlatformKick(uuid, message)) { // handle locally before SENDING a message
JSONObject data = new JSONObject(); JSONObject data = new JSONObject();
@@ -161,13 +160,13 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
unifiedJedis.hset("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", data); unifiedJedis.hset("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", data);
} }
protected void addPlayer(final UUID uuid, final InetAddress inetAddress) { protected void addPlayer(final UUID uuid, final String name, final InetAddress inetAddress) {
Map<String, String> redisData = new HashMap<>(); Map<String, String> redisData = new HashMap<>();
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("redis-bungee::" + this.networkId + "::player::" + uuid + "::data", redisData);
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);
data.put("uuid", uuid); data.put("uuid", uuid);
@@ -215,6 +214,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);
} }
@@ -228,7 +228,7 @@ public abstract class PlayerDataManager<P, LE, DE, PS extends IPubSubMessageEven
} }
public long getLastOnline(UUID uuid) { public long getLastOnline(UUID uuid) {
return this.lastOnlineCache.get(uuid); return getLastOnlineFromRedis(uuid);
} }
public Multimap<String, UUID> serversToPlayers() { public Multimap<String, UUID> serversToPlayers() {
@@ -245,10 +245,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("redis-bungee::" + 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 +263,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("redis-bungee::" + 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,12 +82,22 @@ 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));
} }

View File

@@ -34,7 +34,7 @@ public class InitialUtils {
} }
long uuidCacheSize = unifiedJedis.hlen("uuid-cache"); long uuidCacheSize = unifiedJedis.hlen("uuid-cache");
if (uuidCacheSize > 750000) { if (uuidCacheSize > 750000) {
plugin.logInfo("Looks like you have a really big UUID cache! Run https://github.com/ProxioDev/Brains"); plugin.logInfo("Looks like you have a really big UUID cache! Run '/rb clean' to remove expired cache entries");
} }
break; break;
} }

View File

@@ -1,2 +1,2 @@
group=com.imaginarycode.minecraft group=com.imaginarycode.minecraft
version=0.12.0 version=0.12.5

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-8.10.1-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

7
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,8 @@ 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
' "$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

22
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,11 +59,11 @@ 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

View File

@@ -1,12 +1,11 @@
plugins { plugins {
`java-library` java
`maven-publish`
id("com.github.johnrengelman.shadow") version "8.1.1" id("com.github.johnrengelman.shadow") version "8.1.1"
id("xyz.jpenilla.run-waterfall") version "2.0.0" 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.guava", "guava")
exclude("com.google.code.gson", "gson") exclude("com.google.code.gson", "gson")
@@ -21,23 +20,10 @@ dependencies {
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 { runWaterfall {
waterfallVersion("1.20") waterfallVersion("1.20")
environment["REDISBUNGEE_PROXY_ID"] = "bungeecord-1" environment["REDISBUNGEE_PROXY_ID"] = "bungeecord-1"
@@ -47,9 +33,6 @@ tasks {
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") {
@@ -81,11 +64,3 @@ tasks {
} }
} }
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -0,0 +1,50 @@
plugins {
`java-library`
`maven-publish`
}
dependencies {
api(project(":RedisBungee-API"))
compileOnly(libs.platform.bungeecord) {
exclude("com.google.guava", "guava")
exclude("com.google.code.gson", "gson")
exclude("net.kyori","adventure-api")
}
}
description = "RedisBungee Bungeecord API"
java {
withJavadocJar()
withSourcesJar()
}
tasks {
withType<Javadoc> {
dependsOn(project(":RedisBungee-API").getTasksByName("javadoc", false))
val 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, "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

@@ -15,7 +15,6 @@ 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.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.serializer.bungeecord.BungeeComponentSerializer; import net.kyori.adventure.text.serializer.bungeecord.BungeeComponentSerializer;
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;
@@ -35,25 +34,21 @@ public class BungeePlayerDataManager extends PlayerDataManager<ProxiedPlayer, Po
super(plugin); super(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 @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();
@@ -66,14 +61,21 @@ public class BungeePlayerDataManager extends PlayerDataManager<ProxiedPlayer, Po
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) {
if (plugin.configuration().kickWhenOnline()) { // because something can go wrong and proxy somehow does not update player data correctly on shutdown
kickPlayer(event.getConnection().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation()); // we have to check proxy if it has the player
// wait 3 seconds before releasing the event String proxyId = getProxyFor(event.getConnection().getUniqueId());
plugin.executeAsyncAfter(() -> event.completeIntent((Plugin) plugin), TimeUnit.SECONDS, 3); if (proxyId == null || !plugin.proxyDataManager().isPlayerTrulyOnProxy(proxyId, event.getConnection().getUniqueId())) {
} else {
event.setCancelled(true);
event.setCancelReason(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().alreadyLoggedIn()));
event.completeIntent((Plugin) plugin); event.completeIntent((Plugin) plugin);
} else {
if (plugin.configuration().kickWhenOnline()) {
kickPlayer(event.getConnection().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation());
// wait 3 seconds before releasing the event
plugin.executeAsyncAfter(() -> event.completeIntent((Plugin) plugin), TimeUnit.SECONDS, 3);
} else {
event.setCancelled(true);
event.setCancelReason(BungeeComponentSerializer.get().serialize(plugin.langConfiguration().messages().alreadyLoggedIn()));
event.completeIntent((Plugin) plugin);
}
} }
} else { } else {
event.completeIntent((Plugin) plugin); event.completeIntent((Plugin) plugin);
@@ -81,13 +83,11 @@ public class BungeePlayerDataManager extends PlayerDataManager<ProxiedPlayer, Po
} }
@Override
@EventHandler @EventHandler
public void onLoginEvent(PostLoginEvent event) { public void onLoginEvent(PostLoginEvent event) {
super.addPlayer(event.getPlayer().getUniqueId(), 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

@@ -1,25 +1,11 @@
plugins { plugins {
`java-library` java
`maven-publish`
id("com.github.johnrengelman.shadow") version "8.1.1" id("com.github.johnrengelman.shadow") version "8.1.1"
id("xyz.jpenilla.run-velocity") version "2.0.0" id("xyz.jpenilla.run-velocity") version "2.0.0"
} }
dependencies { dependencies {
api(project(":RedisBungee-API")) { implementation(project(":RedisBungee-Velocity"))
// 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) compileOnly(libs.platform.velocity)
annotationProcessor(libs.platform.velocity) annotationProcessor(libs.platform.velocity)
implementation(project(":RedisBungee-Commands")) implementation(project(":RedisBungee-Commands"))
@@ -30,22 +16,10 @@ dependencies {
description = "RedisBungee Velocity implementation" description = "RedisBungee Velocity 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://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 { runVelocity {
velocityVersion("3.3.0-SNAPSHOT") velocityVersion("3.3.0-SNAPSHOT")
environment["REDISBUNGEE_PROXY_ID"] = "velocity-1" environment["REDISBUNGEE_PROXY_ID"] = "velocity-1"
@@ -55,9 +29,6 @@ tasks {
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()
} }
@@ -75,10 +46,3 @@ tasks {
} }
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -26,7 +26,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;
@@ -146,8 +145,11 @@ public class RedisBungeeListener {
return; return;
} }
} }
try {
((ServerConnection) event.getSource()).sendPluginMessage(event.getIdentifier(), out.toByteArray()); // ServerConnection throws IllegalStateException when connection dies somehow so just ignore :/
((ServerConnection) event.getSource()).sendPluginMessage(event.getIdentifier(), out.toByteArray());
} catch (IllegalStateException ignored) {
}
}); });
} }

View File

@@ -68,7 +68,7 @@ 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, ServerObjectFetcher {
private final ProxyServer server; private final ProxyServer server;
private final Logger logger; private final Logger logger;
private final Path dataFolder; private final Path dataFolder;

View File

@@ -33,25 +33,21 @@ public class VelocityPlayerDataManager extends PlayerDataManager<Player, PostLog
super(plugin); super(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 @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();
@@ -68,26 +64,31 @@ public class VelocityPlayerDataManager extends PlayerDataManager<Player, PostLog
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) {
if (plugin.configuration().kickWhenOnline()) { // because something can go wrong and proxy somehow does not update player data correctly on shutdown
kickPlayer(event.getPlayer().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation()); // we have to check proxy if it has the player
// wait 3 seconds before releasing the event String proxyId = getProxyFor(event.getPlayer().getUniqueId());
plugin.executeAsyncAfter(continuation::resume, TimeUnit.SECONDS, 3); if (proxyId == null || !plugin.proxyDataManager().isPlayerTrulyOnProxy(proxyId, event.getPlayer().getUniqueId())) {
} else {
event.setResult(ResultedEvent.ComponentResult.denied(plugin.langConfiguration().messages().alreadyLoggedIn()));
continuation.resume(); continuation.resume();
} else {
if (plugin.configuration().kickWhenOnline()) {
kickPlayer(event.getPlayer().getUniqueId(), plugin.langConfiguration().messages().loggedInFromOtherLocation());
// wait 3 seconds before releasing the event
plugin.executeAsyncAfter(continuation::resume, TimeUnit.SECONDS, 3);
} else {
event.setResult(ResultedEvent.ComponentResult.denied(plugin.langConfiguration().messages().alreadyLoggedIn()));
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().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,61 @@
plugins {
`java-library`
`maven-publish`
}
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)
}
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(17)
}
javadoc {
options.encoding = Charsets.UTF_8.name()
}
processResources {
filteringCharset = Charsets.UTF_8.name()
}
}
publishing {
publications {
create<MavenPublication>("maven") {
from(components["java"])
}
}
}

View File

@@ -49,7 +49,7 @@ public class RedisBungeeAPI extends AbstractRedisBungeeAPI {
public final ServerInfo getServerFor(@NonNull UUID player) { public final ServerInfo getServerFor(@NonNull UUID player) {
String serverName = this.getServerNameFor(player); String serverName = this.getServerNameFor(player);
if (serverName == null) return null; if (serverName == null) return null;
return ((RedisBungeeVelocityPlugin) this.plugin).getProxy().getServer(serverName).map((RegisteredServer::getServerInfo)).orElse(null); return ((ServerObjectFetcher) this.plugin).getProxy().getServer(serverName).map((RegisteredServer::getServerInfo)).orElse(null);
} }
/** /**

View File

@@ -0,0 +1,10 @@
package com.imaginarycode.minecraft.redisbungee;
import com.velocitypowered.api.proxy.ProxyServer;
public interface ServerObjectFetcher {
ProxyServer getProxy();
}

View File

@@ -4,12 +4,31 @@ pluginManagement {
} }
} }
rootProject.name = "RedisBungee-Parent" rootProject.name = "ValioBungee"
include(":RedisBungee-API")
project(":RedisBungee-API").projectDir = file("api")
include(":RedisBungee-Commands")
project(":RedisBungee-Commands").projectDir = file("commands")
include(":RedisBungee-Velocity") include(":RedisBungee-Velocity")
include(":RedisBungee-Commands") project(":RedisBungee-Velocity").projectDir = file("proxies/velocity")
include(":RedisBungee-Bungee") include(":RedisBungee-Bungee")
include(":RedisBungee-API") project(":RedisBungee-Bungee").projectDir = file("proxies/bungeecord/bungeecord-api")
include(":RedisBungee-Proxy-Bungee")
project(":RedisBungee-Proxy-Bungee").projectDir = file("proxies/bungeecord")
include(":RedisBungee-Velocity")
project(":RedisBungee-Velocity").projectDir = file("proxies/velocity/velocity-api")
include(":RedisBungee-Proxy-Velocity")
project(":RedisBungee-Proxy-Velocity").projectDir = file("proxies/velocity")
dependencyResolutionManagement { dependencyResolutionManagement {
repositories { repositories {
@@ -37,7 +56,7 @@ dependencyResolutionManagement {
val caffeineVersion = "3.1.8" val caffeineVersion = "3.1.8"
val adventureVersion = "4.16.0" val adventureVersion = "4.16.0"
val acf = "0.5.1-SNAPSHOT" val acf = "0.5.1-SNAPSHOT"
val bungeecordApiVersion = "1.20-R0.1-SNAPSHOT" val bungeecordApiVersion = "1.21-R0.1-SNAPSHOT"
val velocityVersion = "3.3.0-SNAPSHOT"; val velocityVersion = "3.3.0-SNAPSHOT";
@@ -73,4 +92,4 @@ dependencyResolutionManagement {
} }
} }