Suggestion to fix #1946: BungeeCord Plugin
TheMuffinPony opened this issue ยท 4 comments
Hello,
As some of you might know, I left an issue a while back, specifically #1946 (which is about the inconsistency between BungeeCord servers). I have a suggestion that can fix it: A BungeeCord plugin.
I'm not 100% sure about Bungee plugins, but somehow each Essentials plugin takes commands from the BungeeCord plugin. For instance, let's suppose there's a two-minute cooldown between using /heal
. Assuming servers had synced health, you could go to server 1, use /heal, go to server 2, and use /heal successfully again (despite there still being an active cooldown on server 1).
Now, let's assume that the BungeeCord plugin was properly installed and configured. Our player does /heal. This makes Essentials on server 1 tell the Bungee server "Player foo used /heal; cooldown disables at " (but with UUIDs). Then, the Bungee server remembers that. Once foo joins another server, the Bungee server tells that server "Enable heal cooldown for foo until ."
This would also make Essentials banning even better, as the server would just tell the Bungee server Bar banned Foo because 'Demo ban'
, and then the Bungee server would worry about keeping Foo banned. There might be a config option to send the ban to all servers (although, it shouldn't be necessary, since anyone running Bungee should be using iptables or some other mechanism to keep players from directly joining a server).
Servers could also be grouped, i.e. if you had two synced survival servers, you could preserve the cooldown between servers, but not have it transfer to a creative server.
Broadcast could also be sent to all servers; /tpa
could work between servers, etc.
Now, as I said earlier, I have no idea how Bungee plugins work, so I don't know how possible this is.
Or just install a mysql based command cooldown plugin for Spigot and handle bans on the BungeeCord (And if you want, sync them back to spigot)
Again Essentials isn't designed for multiserver at all.
EDIT: essay incoming
The approach described by @TheMuffinPony is the obvious approach taken by most plugins that sync over BungeeCord - listen to events and send BungeeCord plugin messages between servers through the plugin - and it seems like a sensible suggestion.
In fact, I started to implement this as a standalone plugin not too long ago, to avoid needing to actually modify EssentialsX to support syncing (as some server owners won't want those features), but it was held up for a few different reasons.
One issue that hinders this approach is that in order for BungeeCord plugin messages to work, there must be a player connected through the BungeeCord proxy to each Minecraft server at all times. If no players are online on any one server on the network, there isn't a pathway to send data across to that server, so that server will gradually fall out of sync with other servers and some kind of replay mechanism would be necessary.
To avoid this, it would likely be necessary to sync the data through an external mechanism such as Redis PubSub, but this still requires that either every server is always online or a queue is created for offline servers to be able to catch up on missed data changes.
Another key problem that held up the progress of my plugin, though, is that this approach is susceptible to infinite loops. For example, say there are three servers on a network; Server 1, Server 2 and Server 3. When a player decides to change his nickname:
- Player A runs
/nick Bob
on Server 1. - Server 1 changes Player A's nickname to Bob.
- Server 1 syncs the changed nickname, sending a message to Server 2 and Server 3 to say "Player A's nickname changed to Bob".
- Server 2 and Server 3 receive this message and both change Player A's nickname to "Bob".
- Server 2 and Server 3 both sync their changed nicknames, each sending messages to Server 1 and each other to say "Player A's nickname changed to Bob".
- Server 1, Server 2 and Server 3 now all change Player A's nickname again.
- Server 1, Server 2 and Server 3 all sync the nickname to each other again, sending another message to each other, and so the loop carries on.
One way to avoid this is to check if a message has been sent recently and discard it if it has (check against a cache of messages), but this may be unreliable if lots of messages are sent and there is a high latency between servers.
Another way to avoid this is to check if the data sent in the message is actually different to what's currently set on the user, but this adds additional calls each time data is synced and could cause unintended side effects (like changing people's display names unintentionally).
A third way is to only attempt to send data to other servers if it wasn't set by the sync code. This is efficient as it doesn't require extra calls, but instead, implementing it would require extending EssentialsX's API to accommodate for this (namely adding a boolean propagate
argument overload every method that triggers a sync). This means it would require more effort to implement this in a separate plugin, as it is fully dependent on EssentialsX adding the required hooks.
The third approach to deduplicating messages looks like the most realistic option to avoid infinite loops, while using an external mechanism like an SQL database or Redis as a form of queue would likely be necessary to avoid servers ending up out of sync. This could also later be extended to support Nucleus (which imho would be absolutely amazing to see), but overall the whole system would take a lot of time and effort to get right just for EssentialsX.
/essay
I think this should add the ability to sync the chat messages across servers in bungeecord.
@felix920506 That is the job of a fully featured chat plugin, not EssentialsX.