Skip to content

Commit

Permalink
feat: Add basic API for server links (#1353)
Browse files Browse the repository at this point in the history
* feat: add basic server links API

* refactor: more precondition checking on links

* refactor: remove whitespace

* refactor: adjust method order, JDs in ServerLink

* refactor: remove "throws" from constructors

* refactor: add @NotNull annotations

* refactor: requested changes

* refactor: just use `List#copyOf`
  • Loading branch information
WiIIiam278 committed Jun 18, 2024
1 parent e60e206 commit 9d25d30
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 0 deletions.
13 changes: 13 additions & 0 deletions api/src/main/java/com/velocitypowered/api/proxy/Player.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.api.util.ModInfo;
import com.velocitypowered.api.util.ServerLink;
import java.net.InetSocketAddress;
import java.util.Collection;
import java.util.List;
Expand Down Expand Up @@ -461,4 +462,16 @@ default void openBook(@NotNull Book book) {
* @sinceMinecraft 1.20.5
*/
void requestCookie(Key key);

/**
* Send the player a list of custom links to display in their client's pause menu.
*
* <p>Note that later packets sent by the backend server may override links sent by the proxy.
*
* @param links an ordered list of {@link ServerLink}s to send to the player
* @throws IllegalArgumentException if the player is from a version lower than 1.21
* @since 3.3.0
* @sinceMinecraft 1.21
*/
void setServerLinks(@NotNull List<ServerLink> links);
}
101 changes: 101 additions & 0 deletions api/src/main/java/com/velocitypowered/api/util/ServerLink.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
/*
* Copyright (C) 2021-2024 Velocity Contributors
*
* The Velocity API is licensed under the terms of the MIT License. For more details,
* reference the LICENSE file in the api top-level directory.
*/

package com.velocitypowered.api.util;

import com.google.common.base.Preconditions;
import java.net.URI;
import java.util.Optional;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;

/**
* Represents a custom URL servers can show in player pause menus.
* Links can be of a built-in type or use a custom component text label.
*/
public final class ServerLink {

private @Nullable Type type;
private @Nullable Component label;
private final URI url;

private ServerLink(Component label, String url) {
this.label = Preconditions.checkNotNull(label, "label");
this.url = URI.create(url);
}

private ServerLink(Type type, String url) {
this.type = Preconditions.checkNotNull(type, "type");
this.url = URI.create(url);
}

/**
* Construct a server link with a custom component label.
*
* @param label a custom component label to display
* @param link the URL to open when clicked
*/
public static ServerLink serverLink(Component label, String link) {
return new ServerLink(label, link);
}

/**
* Construct a server link with a built-in type.
*
* @param type the {@link Type built-in type} of link
* @param link the URL to open when clicked
*/
public static ServerLink serverLink(Type type, String link) {
return new ServerLink(type, link);
}

/**
* Get the type of the server link.
*
* @return the type of the server link
*/
public Optional<Type> getBuiltInType() {
return Optional.ofNullable(type);
}

/**
* Get the custom component label of the server link.
*
* @return the custom component label of the server link
*/
public Optional<Component> getCustomLabel() {
return Optional.ofNullable(label);
}

/**
* Get the link {@link URI}.
*
* @return the link {@link URI}
*/
public URI getUrl() {
return url;
}

/**
* Built-in types of server links.
*
* @apiNote {@link Type#BUG_REPORT} links are shown on the connection error screen
*/
public enum Type {
BUG_REPORT,
COMMUNITY_GUIDELINES,
SUPPORT,
STATUS,
FEEDBACK,
COMMUNITY,
WEBSITE,
FORUMS,
NEWS,
ANNOUNCEMENTS
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import com.velocitypowered.api.proxy.server.RegisteredServer;
import com.velocitypowered.api.util.GameProfile;
import com.velocitypowered.api.util.ModInfo;
import com.velocitypowered.api.util.ServerLink;
import com.velocitypowered.proxy.VelocityServer;
import com.velocitypowered.proxy.adventure.VelocityBossBarImplementation;
import com.velocitypowered.proxy.connection.MinecraftConnection;
Expand Down Expand Up @@ -83,6 +84,7 @@
import com.velocitypowered.proxy.protocol.packet.chat.PlayerChatCompletionPacket;
import com.velocitypowered.proxy.protocol.packet.chat.builder.ChatBuilderFactory;
import com.velocitypowered.proxy.protocol.packet.chat.legacy.LegacyChatPacket;
import com.velocitypowered.proxy.protocol.packet.config.ClientboundServerLinksPacket;
import com.velocitypowered.proxy.protocol.packet.config.StartUpdatePacket;
import com.velocitypowered.proxy.protocol.packet.title.GenericTitlePacket;
import com.velocitypowered.proxy.protocol.util.ByteBufDataOutput;
Expand Down Expand Up @@ -1059,6 +1061,22 @@ public void requestCookie(final Key key) {
}, connection.eventLoop());
}

@Override
public void setServerLinks(final @NotNull List<ServerLink> links) {
Preconditions.checkNotNull(links, "links");
Preconditions.checkArgument(
this.getProtocolVersion().noLessThan(ProtocolVersion.MINECRAFT_1_21),
"Player version must be at least 1.21 to be able to set server links");

if (connection.getState() != StateRegistry.PLAY
&& connection.getState() != StateRegistry.CONFIG) {
throw new IllegalStateException("Can only send server links in CONFIGURATION or PLAY protocol");
}

connection.write(new ClientboundServerLinksPacket(List.copyOf(links).stream()
.map(l -> new ClientboundServerLinksPacket.ServerLink(l, getProtocolVersion())).toList()));
}

@Override
public void addCustomChatCompletions(@NotNull Collection<String> completions) {
Preconditions.checkNotNull(completions, "completions");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.velocitypowered.proxy.protocol.packet.config;

import com.velocitypowered.api.network.ProtocolVersion;
import com.velocitypowered.api.util.ServerLink;
import com.velocitypowered.proxy.connection.MinecraftSessionHandler;
import com.velocitypowered.proxy.protocol.MinecraftPacket;
import com.velocitypowered.proxy.protocol.ProtocolUtils;
Expand Down Expand Up @@ -66,6 +67,13 @@ public List<ServerLink> getServerLinks() {
}

public record ServerLink(int id, ComponentHolder displayName, String url) {

public ServerLink(com.velocitypowered.api.util.ServerLink link, ProtocolVersion protocolVersion) {
this(link.getBuiltInType().map(Enum::ordinal).orElse(-1),
link.getCustomLabel().map(c -> new ComponentHolder(protocolVersion, c)).orElse(null),
link.getUrl().toString());
}

private static ServerLink read(ByteBuf buf, ProtocolVersion version) {
if (buf.readBoolean()) {
return new ServerLink(ProtocolUtils.readVarInt(buf), null, ProtocolUtils.readString(buf));
Expand Down

0 comments on commit 9d25d30

Please sign in to comment.