-
Notifications
You must be signed in to change notification settings - Fork 1
Discord rich presence support for various client mods #666
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
JakeMT04
wants to merge
27
commits into
main
Choose a base branch
from
feat/lunar
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 8 commits
Commits
Show all changes
27 commits
Select commit
Hold shift + click to select a range
116a921
feat: slightly less turbo trash lunar impl
JakeMT04 8fd9ca9
feat: feather support for rich presence
JakeMT04 f3831fa
feat: discord presence updates on state changes (mostly)
JakeMT04 fe82889
chore: notnull annotations
JakeMT04 e01de3d
chore: update comment
JakeMT04 7ac5ac5
chore: split util into its own class
JakeMT04 2e9236c
feat: labymod RPC impl
JakeMT04 f958049
chore: cleanup
JakeMT04 3966f34
chore: remove labymod for now
JakeMT04 eec1502
chore: annotations
JakeMT04 8f235ba
chore: static gson (oops)
JakeMT04 2ca1810
fix: hub rich presence to feature and event rather than delay
JakeMT04 c9eefcf
chore: rename wordutil
JakeMT04 d9e954b
Merge branch 'main' into feat/lunar
ThatGravyBoat cdf33dd
Merge remote-tracking branch 'origin/main' into feat/lunar
ThatGravyBoat 6a07cb6
chore: temporarily include apollo protobufs while lunar is fixing jso…
ThatGravyBoat 8b419c3
Merge branch 'main' into feat/lunar
ThatGravyBoat c50c53a
fix: bad merge
ThatGravyBoat 54b3506
fix: discord rich presence on lunar
ThatGravyBoat 32c1db8
fix: lunar discord rich presence (there is no docs on what the client…
ThatGravyBoat e1c1e4b
lunar sucks so time to see where these fields show up to
ThatGravyBoat 333ea70
lets see if this is good enough for lunar
ThatGravyBoat b71ae6c
lets see if this is good enough for lunar round 2
ThatGravyBoat 6b972a9
Merge branch 'main' into feat/lunar
ThatGravyBoat 009a157
lunar doesnt like our special slash
ThatGravyBoat b990ca9
I was finally told how lunar uses these magic values and its dumb
ThatGravyBoat 0553277
lunar still needs a special slash
ThatGravyBoat File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
12 changes: 12 additions & 0 deletions
12
modules/common/src/main/java/net/hollowcube/common/util/WordUtil.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package net.hollowcube.common.util; | ||
|
|
||
| public class WordUtil { | ||
| public static String indefiniteArticle(final String word) { | ||
| // building -> a building | ||
| // adventure -> an adventure | ||
| return switch (word.charAt(0)) { | ||
| case 'a', 'e', 'i', 'o', 'u' -> "an"; | ||
| default -> "a"; | ||
| } + " " + word; | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
35 changes: 35 additions & 0 deletions
35
...es/compat/src/main/java/net/hollowcube/compat/api/discord/DiscordRichPresenceManager.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package net.hollowcube.compat.api.discord; | ||
|
|
||
| import net.minestom.server.entity.Player; | ||
|
|
||
| import java.util.HashSet; | ||
| import java.util.ServiceLoader; | ||
| import java.util.Set; | ||
|
|
||
|
|
||
| public class DiscordRichPresenceManager { | ||
| private static final Set<DiscordRichPresenceProvider> PROVIDERS = new HashSet<>(); | ||
|
|
||
| static { | ||
| ServiceLoader.load(DiscordRichPresenceProvider.class).forEach(PROVIDERS::add); | ||
| } | ||
|
|
||
|
|
||
| public static void setRichPresence(Player player, String playerState, String gameName, String gameVariantName) { | ||
| for (DiscordRichPresenceProvider provider : PROVIDERS) { | ||
| if (provider.isRichPresenceSupportedFor(player)) { | ||
| provider.setRichPresence(player, playerState, gameName, gameVariantName); | ||
| return; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public static void clearRichPresence(Player player) { | ||
| for (DiscordRichPresenceProvider provider : PROVIDERS) { | ||
| if (provider.isRichPresenceSupportedFor(player)) { | ||
| provider.clearRichPresence(player); | ||
| return; | ||
| } | ||
| } | ||
| } | ||
| } |
11 changes: 11 additions & 0 deletions
11
...s/compat/src/main/java/net/hollowcube/compat/api/discord/DiscordRichPresenceProvider.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package net.hollowcube.compat.api.discord; | ||
|
|
||
| import net.minestom.server.entity.Player; | ||
|
|
||
| public interface DiscordRichPresenceProvider { | ||
| void setRichPresence(Player player, String playerState, String gameName, String gameVariantName); | ||
JakeMT04 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| void clearRichPresence(Player player); | ||
|
|
||
| boolean isRichPresenceSupportedFor(Player player); | ||
| } | ||
151 changes: 151 additions & 0 deletions
151
modules/compat/src/main/java/net/hollowcube/compat/feather/FeatherCompatProvider.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| package net.hollowcube.compat.feather; | ||
|
|
||
| import com.google.auto.service.AutoService; | ||
| import net.digitalingot.feather.serverapi.messaging.*; | ||
| import net.digitalingot.feather.serverapi.messaging.messages.client.S2CClearDiscordActivity; | ||
| import net.digitalingot.feather.serverapi.messaging.messages.client.S2CHandshake; | ||
| import net.digitalingot.feather.serverapi.messaging.messages.client.S2CSetDiscordActivity; | ||
| import net.digitalingot.feather.serverapi.messaging.messages.server.C2SClientHello; | ||
| import net.digitalingot.feather.serverapi.messaging.messages.server.C2SHandshake; | ||
| import net.hollowcube.compat.api.CompatProvider; | ||
| import net.hollowcube.compat.api.discord.DiscordRichPresenceProvider; | ||
| import net.hollowcube.compat.api.packet.PacketRegistry; | ||
| import net.hollowcube.compat.feather.packets.ClientboundFeatherPacket; | ||
| import net.hollowcube.compat.feather.packets.ServerboundFeatherPacket; | ||
| import net.minestom.server.entity.Player; | ||
| import net.minestom.server.event.GlobalEventHandler; | ||
| import net.minestom.server.event.player.PlayerDisconnectEvent; | ||
| import net.minestom.server.tag.Tag; | ||
|
|
||
| import java.util.HashMap; | ||
| import java.util.Map; | ||
| import java.util.UUID; | ||
|
|
||
| @AutoService({CompatProvider.class, DiscordRichPresenceProvider.class}) | ||
| public class FeatherCompatProvider implements CompatProvider, DiscordRichPresenceProvider { | ||
| private static final String IMAGE_URL = "https://servermappings.lunarclientcdn.com/logos/hollowcube.png"; | ||
| private static final Tag<Boolean> FEATHER_SUPPORT_ENABLED = Tag.Transient("mapmaker:feather/enabled"); | ||
| private static final Handshaking HANDSHAKING = new Handshaking(); | ||
|
|
||
| @Override | ||
| public void registerListeners(GlobalEventHandler events) { | ||
| events.addListener(PlayerDisconnectEvent.class, e -> HANDSHAKING.finish(e.getPlayer())); | ||
|
|
||
| } | ||
|
|
||
| @Override | ||
| public void registerPackets(PacketRegistry registry) { | ||
| registry.register(ClientboundFeatherPacket.TYPE); | ||
| registry.register(ServerboundFeatherPacket.TYPE, (player, packet) -> { | ||
| if (!player.hasTag(FEATHER_SUPPORT_ENABLED)) { | ||
| final var hello = HANDSHAKING.handle(player, packet.message()); | ||
|
|
||
| if (hello != null) { | ||
| player.setTag(FEATHER_SUPPORT_ENABLED, true); | ||
| } | ||
|
|
||
| } | ||
| }); | ||
| } | ||
|
|
||
| @Override | ||
| public void setRichPresence(Player player, String playerState, String gameName, String gameVariantName) { | ||
| new ClientboundFeatherPacket( | ||
| new S2CSetDiscordActivity( | ||
| IMAGE_URL, | ||
| "Hollow Cube", | ||
| gameVariantName, | ||
| playerState + " " + gameName + " on Hollow Cube", | ||
| null, | ||
| null, | ||
| null, | ||
| null | ||
| ) | ||
| ).send(player); | ||
| } | ||
|
|
||
| @Override | ||
| public void clearRichPresence(Player player) { | ||
| new ClientboundFeatherPacket(new S2CClearDiscordActivity()).send(player); | ||
| } | ||
|
|
||
| @Override | ||
| public boolean isRichPresenceSupportedFor(Player player) { | ||
| return player.hasTag(FEATHER_SUPPORT_ENABLED); | ||
| } | ||
|
|
||
| // This is directly copied from https://github.com/FeatherMC/feather-server-api/blob/main/bukkit/src/main/java/net/digitalingot/feather/serverapi/bukkit/messaging/BukkitMessagingService.java | ||
| // but with some modifications to make it work with Minestom | ||
| private static class Handshaking { | ||
| private final Map<UUID, HandshakeState> handshakes = new HashMap<>(); | ||
|
|
||
|
|
||
| private HandshakeState getState(Player player) { | ||
| return this.handshakes.getOrDefault(player.getUuid(), HandshakeState.EXPECTING_HANDSHAKE); | ||
| } | ||
|
|
||
| private void setState(UUID playerId, HandshakeState state) { | ||
| this.handshakes.put(playerId, state); | ||
| } | ||
|
|
||
| private void accept(Player player) { | ||
| setState(player.getUuid(), HandshakeState.EXPECTING_HELLO); | ||
| new ClientboundFeatherPacket(new S2CHandshake()).send(player); | ||
| } | ||
|
|
||
| private void reject(Player player) { | ||
| setState(player.getUuid(), HandshakeState.REJECTED); | ||
| } | ||
|
|
||
| private void finish(Player player) { | ||
| this.handshakes.remove(player.getUuid()); | ||
| } | ||
|
|
||
| private C2SClientHello handle(Player player, Message<ServerMessageHandler> message) { | ||
| HandshakeState state = getState(player); | ||
|
|
||
| if (state == HandshakeState.REJECTED) { | ||
| return null; | ||
| } | ||
|
|
||
|
|
||
| if (state == HandshakeState.EXPECTING_HANDSHAKE) { | ||
| if (handleExpectingHandshake(message)) { | ||
| accept(player); | ||
| } else { | ||
| reject(player); | ||
| } | ||
| } else if (state == HandshakeState.EXPECTING_HELLO) { | ||
| if ((message instanceof C2SClientHello)) { | ||
| finish(player); | ||
| return (C2SClientHello) message; | ||
| } | ||
| reject(player); | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| private boolean handleExpectingHandshake(Message<ServerMessageHandler> message) { | ||
| if (!(message instanceof C2SHandshake handshake)) { | ||
| return false; | ||
| } | ||
| int protocolVersion = handshake.getProtocolVersion(); | ||
| if (protocolVersion > MessageConstants.VERSION) { | ||
| // In the official API Implementation, a mismatched API version just alerts players with a permission that it is out of date. | ||
| // It still processes packets fine. | ||
| // There is no indication of what versioning compatibility we can expect since they've only released one version. | ||
| // For now, we can probably just ignore this. | ||
| } | ||
| return true; | ||
| } | ||
|
|
||
|
|
||
| private enum HandshakeState { | ||
| EXPECTING_HANDSHAKE, | ||
| EXPECTING_HELLO, | ||
| REJECTED | ||
| } | ||
| } | ||
|
|
||
| } |
35 changes: 35 additions & 0 deletions
35
.../compat/src/main/java/net/hollowcube/compat/feather/packets/ClientboundFeatherPacket.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| package net.hollowcube.compat.feather.packets; | ||
|
|
||
| import net.digitalingot.feather.serverapi.messaging.ClientMessageHandler; | ||
| import net.digitalingot.feather.serverapi.messaging.Message; | ||
| import net.digitalingot.feather.serverapi.messaging.MessageDecoder; | ||
| import net.digitalingot.feather.serverapi.messaging.MessageEncoder; | ||
| import net.hollowcube.compat.api.packet.ClientboundModPacket; | ||
| import net.minestom.server.network.NetworkBuffer; | ||
| import org.jetbrains.annotations.NotNull; | ||
|
|
||
| // Feather supports a fragmented packet channel for messages that exceed the packet size limit, which was set lower on older versions of Bukkit | ||
| // We don't ever send messages that get that big, so for now this can be ignored. | ||
| // If we ever utilise more of their UI features, this may be needed in the future. | ||
| public record ClientboundFeatherPacket( | ||
| @NotNull Message<ClientMessageHandler> message | ||
| ) implements ClientboundModPacket<ClientboundFeatherPacket> { | ||
| public static final Type<ClientboundFeatherPacket> TYPE = Type.of( | ||
| "feather", | ||
| "client", | ||
| NetworkBuffer.RAW_BYTES.transform(ClientboundFeatherPacket::new, ClientboundFeatherPacket::toBytes) | ||
| ); | ||
|
|
||
| private ClientboundFeatherPacket(byte[] bytes) { | ||
| this(MessageDecoder.CLIENT_BOUND.decode(bytes)); | ||
| } | ||
|
|
||
| public byte[] toBytes() { | ||
| return MessageEncoder.CLIENT_BOUND.encode(message); | ||
| } | ||
|
|
||
| @Override | ||
| public Type<ClientboundFeatherPacket> getType() { | ||
| return TYPE; | ||
| } | ||
| } |
32 changes: 32 additions & 0 deletions
32
.../compat/src/main/java/net/hollowcube/compat/feather/packets/ServerboundFeatherPacket.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package net.hollowcube.compat.feather.packets; | ||
|
|
||
| import net.digitalingot.feather.serverapi.messaging.Message; | ||
| import net.digitalingot.feather.serverapi.messaging.MessageDecoder; | ||
| import net.digitalingot.feather.serverapi.messaging.MessageEncoder; | ||
| import net.digitalingot.feather.serverapi.messaging.ServerMessageHandler; | ||
| import net.hollowcube.compat.api.packet.ServerboundModPacket; | ||
| import net.minestom.server.network.NetworkBuffer; | ||
| import org.jetbrains.annotations.NotNull; | ||
|
|
||
| public record ServerboundFeatherPacket( | ||
| @NotNull Message<ServerMessageHandler> message | ||
| ) implements ServerboundModPacket<ServerboundFeatherPacket> { | ||
| public static final Type<ServerboundFeatherPacket> TYPE = Type.of( | ||
| "feather", | ||
| "client", | ||
| NetworkBuffer.RAW_BYTES.transform(ServerboundFeatherPacket::new, ServerboundFeatherPacket::toBytes) | ||
| ); | ||
|
|
||
| private ServerboundFeatherPacket(byte[] bytes) { | ||
| this(MessageDecoder.SERVER_BOUND.decode(bytes)); | ||
| } | ||
|
|
||
| public byte[] toBytes() { | ||
| return MessageEncoder.SERVER_BOUND.encode(message); | ||
| } | ||
|
|
||
| @Override | ||
| public Type<ServerboundFeatherPacket> getType() { | ||
| return TYPE; | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.