Skip to content

Commit

Permalink
Finish JSON lightweight docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ItsNature committed Oct 1, 2024
1 parent 25a6dc2 commit a42f0d3
Show file tree
Hide file tree
Showing 11 changed files with 473 additions and 100 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@
*/
package com.lunarclient.apollo.example.json;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import com.lunarclient.apollo.example.ApolloExamplePlugin;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.bukkit.Bukkit;
Expand All @@ -38,6 +40,34 @@

public final class JsonPacketUtil {

private static final List<String> APOLLO_MODULES = Arrays.asList("limb", "beam", "border", "chat", "colored_fire", "combat", "cooldown",
"entity", "glow", "hologram", "mod_setting", "nametag", "nick_hider", "notification", "packet_enrichment", "rich_presence",
"server_rule", "staff_mod", "stopwatch", "team", "title", "tnt_countdown", "transfer", "vignette", "waypoint"
);

// Module Id -> Option key -> Object
private static final Table<String, String, Object> CONFIG_MODULE_PROPERTIES = HashBasedTable.create();

static {
// Module Options that the client needs to notified about, these properties are sent with the enable module packet
// While using the Apollo plugin this would be equivalent to modifying the config.yml
CONFIG_MODULE_PROPERTIES.put("combat", "disable-miss-penalty", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "competitive-game", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "competitive-commands", Arrays.asList("/server", "/servers", "/hub"));
CONFIG_MODULE_PROPERTIES.put("server_rule", "disable-shaders", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "disable-chunk-reloading", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "disable-broadcasting", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "anti-portal-traps", true);
CONFIG_MODULE_PROPERTIES.put("server_rule", "override-brightness", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "brightness", 50);
CONFIG_MODULE_PROPERTIES.put("server_rule", "override-nametag-render-distance", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "nametag-render-distance", 64);
CONFIG_MODULE_PROPERTIES.put("server_rule", "override-max-chat-length", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "max-chat-length", 256);
CONFIG_MODULE_PROPERTIES.put("tnt_countdown", "tnt-ticks", 80);
CONFIG_MODULE_PROPERTIES.put("waypoint", "server-handles-waypoints", false);
}

public static void sendPacket(Player player, JsonObject message) {
player.sendPluginMessage(ApolloExamplePlugin.getPlugin(), "apollo:json", message.toString().getBytes());
}
Expand All @@ -49,18 +79,6 @@ public static void broadcastPacket(JsonObject message) {
player.sendPluginMessage(ApolloExamplePlugin.getPlugin(), "apollo:json", data));
}

public static void enableModules(Player player, List<String> modules, Table<String, String, Object> properties) {
JsonArray settings = modules.stream()
.map(module -> JsonPacketUtil.createEnableModuleObject(module, properties.row(module)))
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);

JsonObject message = new JsonObject();
message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.configurable.v1.OverrideConfigurableSettingsMessage");
message.add("configurable_settings", settings);

JsonPacketUtil.sendPacket(player, message);
}

public static JsonObject createEnableModuleObject(@NotNull String module, Map<String, Object> properties) {
JsonObject enableModuleObject = new JsonObject();
enableModuleObject.addProperty("apollo_module", module);
Expand Down Expand Up @@ -98,6 +116,18 @@ private static JsonElement convertToJsonElement(Object value) {
throw new RuntimeException("Unable to wrap value of type '" + value.getClass().getSimpleName() + "'!");
}

public static void enableModules(Player player) {
JsonArray settings = APOLLO_MODULES.stream()
.map(module -> JsonPacketUtil.createEnableModuleObject(module, CONFIG_MODULE_PROPERTIES.row(module)))
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);

JsonObject message = new JsonObject();
message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.configurable.v1.OverrideConfigurableSettingsMessage");
message.add("configurable_settings", settings);

JsonPacketUtil.sendPacket(player, message);
}

private JsonPacketUtil() {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,25 @@

public final class JsonUtil {

public static JsonObject createEnableModuleObjectWithType(@NotNull String module, Map<String, Object> properties) {
JsonObject enableModuleObject = JsonPacketUtil.createEnableModuleObject(module, properties);
enableModuleObject.addProperty("@type", "type.googleapis.com/lunarclient.apollo.configurable.v1.ConfigurableSettings");
return enableModuleObject;
}

public static JsonObject createUuidObject(@NotNull UUID uuid) {
JsonObject uuidObject = new JsonObject();
uuidObject.addProperty("high64", Long.toUnsignedString(uuid.getMostSignificantBits()));
uuidObject.addProperty("low64", Long.toUnsignedString(uuid.getLeastSignificantBits()));
return uuidObject;
}

public static JsonObject createColorObject(@NotNull Color color) {
JsonObject colorObject = new JsonObject();
colorObject.addProperty("color", color.getRGB());
return colorObject;
}

public static String createDurationObject(@NotNull Duration duration) {
long seconds = duration.getSeconds();
int nanos = duration.getNano();
Expand All @@ -52,23 +71,20 @@ public static String createDurationObject(@NotNull Duration duration) {
return durationString;
}

public static JsonObject createColorObject(@NotNull Color color) {
JsonObject colorObject = new JsonObject();
colorObject.addProperty("color", color.getRGB());
return colorObject;
}

public static JsonObject createUuidObject(@NotNull UUID uuid) {
JsonObject uuidObject = new JsonObject();
uuidObject.addProperty("high64", Long.toUnsignedString(uuid.getMostSignificantBits()));
uuidObject.addProperty("low64", Long.toUnsignedString(uuid.getLeastSignificantBits()));
return uuidObject;
public static JsonObject createCuboid2DObject(double minX, double minZ, double maxX, double maxZ) {
JsonObject cuboid2DObject = new JsonObject();
cuboid2DObject.addProperty("min_x", minX);
cuboid2DObject.addProperty("min_z", minZ);
cuboid2DObject.addProperty("max_x", maxX);
cuboid2DObject.addProperty("max_z", maxZ);
return cuboid2DObject;
}

public static JsonObject createEnableModuleObjectWithType(@NotNull String module, Map<String, Object> properties) {
JsonObject enableModuleObject = JsonPacketUtil.createEnableModuleObject(module, properties);
enableModuleObject.addProperty("@type", "type.googleapis.com/lunarclient.apollo.configurable.v1.ConfigurableSettings");
return enableModuleObject;
public static JsonObject createEntityIdObject(@NotNull Entity entity) {
JsonObject entityIdObject = new JsonObject();
entityIdObject.addProperty("entity_id", entity.getEntityId());
entityIdObject.add("entity_uuid", JsonUtil.createUuidObject(entity.getUniqueId()));
return entityIdObject;
}

public static JsonObject createLocationObject(@NotNull Location location) {
Expand All @@ -89,22 +105,6 @@ public static JsonObject createBlockLocationObject(@NotNull Location location) {
return locationObject;
}

public static JsonObject createEntityIdObject(@NotNull Entity entity) {
JsonObject entityIdObject = new JsonObject();
entityIdObject.addProperty("entity_id", entity.getEntityId());
entityIdObject.add("entity_uuid", JsonUtil.createUuidObject(entity.getUniqueId()));
return entityIdObject;
}

public static JsonObject createCuboid2DObject(double minX, double minZ, double maxX, double maxZ) {
JsonObject cuboid2DObject = new JsonObject();
cuboid2DObject.addProperty("min_x", minX);
cuboid2DObject.addProperty("min_z", minZ);
cuboid2DObject.addProperty("max_x", maxX);
cuboid2DObject.addProperty("max_z", maxZ);
return cuboid2DObject;
}

public static JsonObject createItemStackIconObject(@Nullable String itemName, int itemId, int customModelData) {
JsonObject itemIconObject = new JsonObject();
if (itemName != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,56 +23,23 @@
*/
package com.lunarclient.apollo.example.json.listeners;

import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import com.google.gson.JsonObject;
import com.lunarclient.apollo.example.ApolloExamplePlugin;
import com.lunarclient.apollo.example.json.JsonPacketUtil;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerRegisterChannelEvent;
import org.bukkit.plugin.messaging.Messenger;

public class ApolloPlayerJsonListener implements Listener {

private static final List<String> APOLLO_MODULES = Arrays.asList("limb", "beam", "border", "chat", "colored_fire", "combat", "cooldown",
"entity", "glow", "hologram", "mod_setting", "nametag", "nick_hider", "notification", "packet_enrichment", "rich_presence",
"server_rule", "staff_mod", "stopwatch", "team", "title", "tnt_countdown", "transfer", "vignette", "waypoint"
);

// Module Id -> Option key -> Object
private static final Table<String, String, Object> CONFIG_MODULE_PROPERTIES = HashBasedTable.create();

static {
// Module Options that the client needs to notified about, these properties are sent with the enable module packet
// While using the Apollo plugin this would be equivalent to modifying the config.yml
CONFIG_MODULE_PROPERTIES.put("combat", "disable-miss-penalty", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "competitive-game", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "competitive-commands", Arrays.asList("/server", "/servers", "/hub"));
CONFIG_MODULE_PROPERTIES.put("server_rule", "disable-shaders", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "disable-chunk-reloading", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "disable-broadcasting", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "anti-portal-traps", true);
CONFIG_MODULE_PROPERTIES.put("server_rule", "override-brightness", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "brightness", 50);
CONFIG_MODULE_PROPERTIES.put("server_rule", "override-nametag-render-distance", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "nametag-render-distance", 64);
CONFIG_MODULE_PROPERTIES.put("server_rule", "override-max-chat-length", false);
CONFIG_MODULE_PROPERTIES.put("server_rule", "max-chat-length", 256);
CONFIG_MODULE_PROPERTIES.put("tnt_countdown", "tnt-ticks", 80);
CONFIG_MODULE_PROPERTIES.put("waypoint", "server-handles-waypoints", false);
}

private static final String REGISTER_CHANNEL = "lunar:apollo"; // Used for detecting whether the player supports Apollo
private static final String LIGHTWEIGHT_CHANNEL = "apollo:json"; // Used for sending and receiving feature packets

private final ApolloExamplePlugin plugin;

private final Set<UUID> playersRunningApollo = new HashSet<>();
Expand All @@ -81,9 +48,9 @@ public ApolloPlayerJsonListener(ApolloExamplePlugin plugin) {
this.plugin = plugin;

Messenger messenger = Bukkit.getServer().getMessenger();
messenger.registerIncomingPluginChannel(plugin, REGISTER_CHANNEL, (s, player, bytes) -> { });
messenger.registerIncomingPluginChannel(plugin, LIGHTWEIGHT_CHANNEL, (s, player, bytes) -> { });
messenger.registerOutgoingPluginChannel(plugin, LIGHTWEIGHT_CHANNEL);
messenger.registerIncomingPluginChannel(plugin, "lunar:apollo", (s, player, bytes) -> { });
messenger.registerIncomingPluginChannel(plugin, "apollo:json", (s, player, bytes) -> { });
messenger.registerOutgoingPluginChannel(plugin, "apollo:json");

Bukkit.getPluginManager().registerEvents(this, plugin);
}
Expand All @@ -92,28 +59,46 @@ public void disable() {
this.playersRunningApollo.clear();

Messenger messenger = Bukkit.getServer().getMessenger();
messenger.unregisterIncomingPluginChannel(this.plugin, REGISTER_CHANNEL);
messenger.unregisterIncomingPluginChannel(this.plugin, LIGHTWEIGHT_CHANNEL);
messenger.unregisterOutgoingPluginChannel(this.plugin, LIGHTWEIGHT_CHANNEL);
messenger.unregisterIncomingPluginChannel(this.plugin, "lunar:apollo");
messenger.unregisterIncomingPluginChannel(this.plugin, "apollo:json");
messenger.unregisterOutgoingPluginChannel(this.plugin, "apollo:json");

HandlerList.unregisterAll(this);
}

@EventHandler
private void onRegisterChannel(PlayerRegisterChannelEvent event) {
if (!event.getChannel().equalsIgnoreCase(REGISTER_CHANNEL)) {
if (!event.getChannel().equalsIgnoreCase("lunar:apollo")) {
return;
}

this.onApolloRegister(event.getPlayer());
}

@EventHandler
private void onPlayerChangedWorld(PlayerChangedWorldEvent event) {
Player player = event.getPlayer();

// Sending the player's world name to the client is required for some modules
JsonPacketUtil.sendPacket(player, this.createUpdatePlayerWorldMessage(player));
}

private JsonObject createUpdatePlayerWorldMessage(Player player) {
JsonObject message = new JsonObject();
message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.player.v1.UpdatePlayerWorldMessage");
message.addProperty("world", player.getWorld().getName());
return message;
}

private boolean isPlayerRunningApollo(Player player) {
return this.playersRunningApollo.contains(player.getUniqueId());
}

private void onApolloRegister(Player player) {
JsonPacketUtil.enableModules(player, APOLLO_MODULES, CONFIG_MODULE_PROPERTIES);
JsonPacketUtil.enableModules(player);

// Sending the player's world name to the client is required for some modules
JsonPacketUtil.sendPacket(player, this.createUpdatePlayerWorldMessage(player));

this.playersRunningApollo.add(player.getUniqueId());
player.sendMessage("You are using LunarClient!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,19 @@ public static Uuid createUuidProto(UUID object) {
.build();
}

public static com.lunarclient.apollo.common.v1.Color createColorProto(Color object) {
return com.lunarclient.apollo.common.v1.Color.newBuilder()
.setColor(object.getRGB())
.build();
}

public static com.google.protobuf.Duration createDurationProto(Duration object) {
return com.google.protobuf.Duration.newBuilder()
.setSeconds(object.getSeconds())
.setNanos(object.getNano())
.build();
}

public static Cuboid2D createCuboid2DProto(double minX, double minZ, double maxX, double maxZ) {
return Cuboid2D.newBuilder()
.setMinX(minX)
Expand All @@ -72,19 +85,6 @@ public static EntityId createEntityIdProto(int id, UUID uuid) {
.build();
}

public static com.lunarclient.apollo.common.v1.Color createColorProto(Color object) {
return com.lunarclient.apollo.common.v1.Color.newBuilder()
.setColor(object.getRGB())
.build();
}

public static com.google.protobuf.Duration createDurationProto(Duration object) {
return com.google.protobuf.Duration.newBuilder()
.setSeconds(object.getSeconds())
.setNanos(object.getNano())
.build();
}

public static com.lunarclient.apollo.common.v1.Location createLocationProto(Location location) {
return com.lunarclient.apollo.common.v1.Location.newBuilder()
.setWorld(location.getWorld().getName())
Expand Down
3 changes: 2 additions & 1 deletion docs/developers/lightweight/_meta.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"introduction": "Introduction",
"protobuf": "Protobuf"
"protobuf": "Protobuf",
"json": "JSON"
}
7 changes: 7 additions & 0 deletions docs/developers/lightweight/json/_meta.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"getting-started": "Getting Started",
"player-detection": "Player Detection",
"packet-util": "Packet Util",
"object-util": "Object Util",
"adventure-util": "Adventure Util"
}
13 changes: 13 additions & 0 deletions docs/developers/lightweight/json/adventure-util.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Adventure Util

## Overview

Provides a single method responsible for serializing the Adventure Component to a String

## Integration

```java
public static String toJson(@NonNull Component component) {
return GsonComponentSerializer.gson().serialize(component);
}
```
22 changes: 22 additions & 0 deletions docs/developers/lightweight/json/getting-started.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Tab, Tabs } from 'nextra-theme-docs'

# Getting Started

## Overview

This method involves manually constructing JSON objects using a JSON library (e.g., Gson) and then converting these objects into byte arrays for transmission. It allows for dynamic and programmatic construction of JSON objects, offering flexibility in modifying the JSON structure. Available fields for each message, including their types, are available on the Buf Schema Registry at https://buf.build/lunarclient/apollo.
While constructing messages, note that the `@type` field isn't required if the message is being sent within a message.

<Callout type="info">
Note that this method uses a different plugin channel for sending packets,
which is `apollo:json`, while still using the `lunar:apollo` for player detection.
</Callout>

## Integration Examples

πŸ”— [Sending Apollo packets & Enabling Apollo modules](/apollo/developers/lightweight/json/packet-util)<br/>
πŸ”— [Detecting players using LunarClient](/apollo/developers/lightweight/json/player-detection)<br/>
πŸ”— [Common Apollo Objects](/apollo/developers/lightweight/json/object-util)<br/>
πŸ”— [Adventure Util](/apollo/developers/lightweight/json/adventure-util)<br/>

TODO mention module examples
Loading

1 comment on commit a42f0d3

@LunarClientBot
Copy link
Collaborator

@LunarClientBot LunarClientBot commented on a42f0d3 Oct 1, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

πŸ“„ Documentation Deployment

Status:❌ Failed
Environment:preview
URL:Pending...

Please sign in to comment.