KoxSosen / SimpleVoiceBans

SimpleVoiceBans provides a simple LibertyBans and SimpleVoiceChat integration.
MIT License
7 stars 1 forks source link

Implement support for proxy based setups. #1

Closed KoxSosen closed 4 months ago

KoxSosen commented 4 months ago

This PR implements support for proxies. In detail, it implements support for setups where LibertyBans is installed on the proxy, and SimpleVoiceChat on all of the backend, and the proxy.

This feature was rather tricky to get working. The initial issue was that SimpleVoiceChat does not provide an API for it's proxy plugin, since it's a simple UDP proxy. This is fine, however this makes it impossible to detect or cancel a player voice chat message only on the proxy. Therefore, we need to detect the message event on the backend, and then somehow determine if the player is muted using an API that is only available on the proxy. (Since LibertyBans is only installed on the proxy.)

Let me introduce you to my proposed solution: The Bungee Plugin Messaging channel. Using this widely supported means of communication, we can reliably communicate between the backend(s) and the proxy to determine if someone is muted or not.

The "data" flow looks something like this:

  1. Player sends voice message to the server. It gets sent from the proxy to the backend.
  2. The relevant event gets fired on the backend. (MicrophonePacketEvent)
  3. SimpleVoiceBans checks if the player is present in the local "cache", a ConcurrentHashMap<k,v>. 3.1 If the player is present: We check if the value assigned to their UUID or IP is true (they are muted), or false (they are not muted). Then, we either cancel the event, or don't do anything. 3.2 If the player is not present: SimpleVoiceBans sends a plugin message to the proxy, containing the player's IP, UUID, essentially "asking" the proxy if the player is muted.
  4. The proxy receives the plugin message event, and using the LibertyBans API preforms the check.
  5. The proxy then responds by sending a plugin message with the results. The response contains the IP, the UUID, and a boolean which determines if the player is muted.
  6. The backend receives the plugin message, and SimpleVoiceBans adds the player to it's internal "cache".
  7. On the next MicrophonePacketEvent sent by the player, we return to step number 3.

Additionally, the proxy plugin sends plugin messages after punishments issued using LibertyBans. It listens to PostPunishmentEvent, as well as PostPardonEvent, and refreshes the cache accordingly.

Since this means of determining whether a player is muted using an API on another platform is well, done using a network request, it is not bulletproof by any means. On the "initial" MicrophonePacketEvent , when the player is not in the local cache, a network request is preformed, which can take some time depending on people's setup. Because it may take a long time to well get a response, we can not block anywhere, so the initial few MicrophonePacketEvent(s) may leak thru, even if the player is muted. There isn't much I can do about this, as I can't just blindly cancel everything until we determine if someone is muted or not.

While I tested this PR to work before the multi-module refactor, there is a bunch of stuff left to do, so I'm marking this as a draft.

Additionally, if you come across this PR, please feel free to review it, and share you opinion. Obviously, this is a big jump from like ~50 lines to ~560, however to my understanding, there isn't really a way around adding some short of messenger unless SimpleVoiceChat decides to add events to it's proxy based implementation. But of course that's up to them, I'm the addon developer, so it's my task to work around stuff if I want to preform an API check on another platform.

KoxSosen commented 4 months ago

Please note: I've considered other means of muting players, such as negating the voicechat.speak permission, or hooking into LuckPerms to achieve something similar. However this would bring another set of issues: