diff --git a/docs/pages/server/addons/betterperspective/index.md b/docs/pages/server/addons/betterperspective/index.md
new file mode 100644
index 0000000..caa317c
--- /dev/null
+++ b/docs/pages/server/addons/betterperspective/index.md
@@ -0,0 +1,104 @@
+The BetterPerspective integration provides the unlock camera permission.
+
+## Adding the Dependency
+
+The BetterPerspective integration is shipped with all official [server platform integration artifacts](/pages/server/#adding-the-labymod-4-server-api-as-a-dependency). If you are using the `core` artifact, you can add the following dependency to your project:
+
+???+ danger "Important Note"
+
+ For the examples below, `VERSION` with the version you want to use. The latest version can be found here: ![GitHub Release](https://img.shields.io/github/v/release/LabyMod/labymod4-server-api-integrations?label=%20)
+
+=== ":octicons-file-code-16: Gradle (Kotlin DSL)"
+
+ ```kotlin
+ dependencies {
+ compileOnly("net.labymod.serverapi.integration:betterperspective:VERSION")
+ }
+ ```
+
+=== ":octicons-file-code-16: Gradle (Groovy)"
+
+ ```groovy
+ dependencies {
+ compileOnly "net.labymod.serverapi.integration:betterperspective:VERSION"
+ }
+ ```
+
+=== ":octicons-file-code-16: Maven"
+
+ ```xml
+
+
+ net.labymod.serverapi.integration
+ betterperspective
+ VERSION
+
+
+ ```
+
+## Unlock Camera Permission
+
+While not necessary to use, the integration provides a constant for the unlock camera permission methods to toggle the permission easily.
+
+???+ tip "Note"
+
+ The Unlock Camera permission is enabled by default.
+
+### Via BetterPerspectivePlayer
+
+=== ":octicons-file-code-16: Disable Unlock Camera"
+
+ ```java
+ // Get the LabyModPlayer
+ LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId);
+
+ // Get the BetterPerspectivePlayer
+ BetterPerspectivePlayer betterPerspectivePlayer = labyModPlayer.getIntegrationPlayer(
+ BetterPerspectivePlayer.class
+ );
+
+ // Disable the permission
+ betterPerspectivePlayer.denyUnlockCamera();
+ ```
+
+=== ":octicons-file-code-16: Enable Unlock Camera"
+
+ ```java
+ // Get the LabyModPlayer
+ LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId);
+
+ // Get the BetterPerspectivePlayer
+ BetterPerspectivePlayer betterPerspectivePlayer = labyModPlayer.getIntegrationPlayer(
+ BetterPerspectivePlayer.class
+ );
+
+ // Enable the permission
+ betterPerspectivePlayer.allowUnlockCamera();
+ ```
+
+### Via the LabyModProtocol
+
+=== ":octicons-file-code-16: Disable Unlock Camera"
+
+ ```java
+ // Get the LabyModProtocol
+ LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol();
+
+ // Send the packet
+ labyModProtocol.sendPacket(uniqueId, new PermissionPacket(
+ BetterPerspectiveIntegration.UNLOCK_CAMERA_PERMISSION.deny()
+ ));
+ ```
+
+=== ":octicons-file-code-16: Enable Unlock Camera"
+
+ ```java
+ // Get the LabyModProtocol
+ LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol();
+
+ // Send the packet
+ labyModProtocol.sendPacket(uniqueId, new PermissionPacket(
+ BetterPerspectiveIntegration.UNLOCK_CAMERA_PERMISSION.allow()
+ ));
+ ```
+
diff --git a/docs/pages/server/labymod/moderation/disable-addons.md b/docs/pages/server/labymod/moderation/disable-addons.md
new file mode 100644
index 0000000..23277b7
--- /dev/null
+++ b/docs/pages/server/labymod/moderation/disable-addons.md
@@ -0,0 +1,95 @@
+???+ warning "Only available on Snapshot"
+ This feature was added in LabyMod 4.2.33 (currently only available on the snapshot release channel).
+
+The `AddonDisablePacket` is a client-bound packet that forcefully disables the specified addons for the player.
+Reverting the forced disabled state is also possible via the same packet.
+
+???+ warning
+ While this should work with all addons that can also be disabled by the user, this cannot be guaranteed. Especially for addons that are not in the addon store.
+
+## Disabling Addons
+
+???+ danger "Note"
+ Some addons also provide special permissions to disable certain features. For user experience sake, please consider disabling these permissions instead of the whole addon (f.e. [BetterPerspective](#)).
+
+### Via LabyModPlayer (Recommended)
+
+```java
+// Create or get a List of addons to disable
+List addonsToDisable = new ArrayList<>();
+
+// Add the namespace of all addons that you want to disable
+addonsToDisable.add("voicechat");
+addonsToDisable.add("clearwater");
+
+// Get the LabyModPlayer
+LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId);
+
+// Send the addons to disable
+labyModPlayer.disableAddons(addons);
+```
+
+### Via the LabyModProtocol
+
+```java
+// Create or get a List of addons to disable (array is also possible)
+List addonsToDisable = new ArrayList<>();
+
+// Add the namespace of all addons that you want to disable
+addonsToDisable.add("voicechat");
+addonsToDisable.add("clearwater");
+
+// Get the LabyModProtocol
+LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol();
+
+// Send the packet
+labyModProtocol.sendPacket(uniqueId, AddonDisablePacket.disable(addonsToDisable));
+```
+
+## Reverting the Disable State
+
+### Via LabyModPlayer (Recommended)
+
+When disabling addons [via LabyModPlayer](#via-labymodplayer-recommended), all disabled addons are stored in the player's object. This allows you to either revert the disable state for all disabled addons or only for specific ones.
+
+=== ":octicons-file-code-16: All Disabled Addons"
+
+ ```java
+ // Get the LabyModPlayer
+ LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId);
+
+ // Revert the disabled state of all disabled addons
+ labyModPlayer.revertDisabledAddons();
+ ```
+
+=== ":octicons-file-code-16: Specific Addons"
+
+ ```java
+ // Create or get a List of addons to enable
+ List addonsToRevert = new ArrayList<>();
+
+ // Add the namespace of all addons that you want to enable
+ addonsToRevert.add("voicechat");
+
+ // Get the LabyModPlayer
+ LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId);
+
+ // Send the addons to revert
+ labyModPlayer.revertDisabledAddons(addonsToRevert);
+ ```
+
+### Via the LabyModProtocol
+
+```java
+// Create or get a List of addons to enable (array is also possible)
+List addonsToRevert = new ArrayList<>();
+
+// Add the namespace of all addons that you want to enable
+addonsToRevert.add("voicechat");
+
+// Get the LabyModProtocol
+LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol();
+
+// Send the packet
+labyModProtocol.sendPacket(uniqueId, AddonDisablePacket.revert(addonsToRevert));
+```
\ No newline at end of file
diff --git a/docs/pages/server/labymod/moderation/installed-addons.md b/docs/pages/server/labymod/moderation/installed-addons.md
new file mode 100644
index 0000000..9c2c13b
--- /dev/null
+++ b/docs/pages/server/labymod/moderation/installed-addons.md
@@ -0,0 +1,132 @@
+???+ warning "Only available on Snapshot"
+ This feature was added in LabyMod 4.2.33 (currently only available on the snapshot release channel).
+
+There are multiple packets related to the installed addons of your players. But all rely on the client-bound packet
+`InstalledAddonsRequestPacket`.
+The workflow is as follows:
+
+1. You send the `InstalledAddonsRequestPacket` to the player containing the addons that you want to request.
+2. The client responds with the `InstalledAddonsResponsePacket` containing all requested addons that are installed.
+3. If the enabled state of a requested addon changes (or it was installed), the client will send the
+ `AddonStateChangedPacket` to the server.
+
+## Get Installed Addons
+
+`LabyModPlayer#installedAddons` gets an object of the class `InstalledAddonsResponse`, this object is created with the `LabyModPlayer` BUT does not contain any addons until you request them. You can check this by calling `#hasResponse` on the object.
+
+This object is also used as response when using the `LabyModPlayer#requestInstalledAddons` method (with callback).
+
+???+ danger "Important Note"
+ Installed addons are not sent to the server by default. You need to request them first, see [Requesting Installed Addons](#requesting-installed-addons).
+
+The `InstalledAddonsResponse` class contains the following methods:
+
+- `#hasResponse` - Whether the client has responded with the installed addons.
+- `#hasRequested` - Whether the installed addons were requested
+- `#getRequested` - Gets the requested addons. If `#hasRequested` is true and the list is empty, all addons were requested.
+- `#isInstalled` - Whether the addon is installed
+- `#isEnabled` - Whether the addon is enabled
+- `#isDisabled` - Whether the addon is disabled
+- `#isLocal` - Returns `true` if the addon is installed locally (`false` if it's from the addon store)
+- `#getVersion` - Gets the version of the addon
+
+## Requesting Installed Addons
+
+As mentioned above **ALL** packets related to installed addons **RELY** on this packet and it's contents. The client **DOES NOT** send the installed addons to the server automatically.
+
+???+ danger "Important Note"
+ Requesting **all** installed addons is not recommended as it can lead to unnecessary traffic and processing. Only request the addons that you really need to know about.
+
+### Via LabyModPlayer (Recommended)
+
+The `LabyModPlayer` object provides the `#installedAddons` method to get the installed addons of the player at any time. Check `InstalledAddonsResponse#hasResponse` before handling it though, to ensure that the data is valid.
+
+???+ warning "Note"
+ Using the `LabyModPlayer` for this process is recommended as it keeps track of the installed and enabled addons for you. If you're not using the `LabyModPlayer`, you need to keep track of the installed (and enabled/disabled) addons yourself by [handling the server-bound packets](/pages/server/protocols/#registering-handlers).
+
+=== ":octicons-file-code-16: Specific Addons"
+
+ ```java
+ // Create or get a List of addons to request
+ List addonsToRequest = new ArrayList<>();
+
+ // Add the namespace of all addons that you want to request
+ // Keeping the List empty requests all addons (not recommended)
+ addonsToRequest.add("voicechat");
+
+ // Get the LabyModPlayer
+ LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId);
+
+ // Request the installed addons and optionally handle the response
+ labyModPlayer.requestInstalledAddons(addonsToRequest, response -> {
+ if (response.isEnabled("voicechat")) {
+ // VoiceChat is enabled
+ } else if (response.isDisabled("voicechat")) {
+ // VoiceChat is disabled
+ } else {
+ // VoiceChat is not installed
+ }
+ });
+ ```
+
+=== ":octicons-file-code-16: All Addons (Not Recommended)"
+
+ ```java
+ // Get the LabyModPlayer
+ LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId);
+
+ // Request all installed addons and optionally handle the response
+ labyModPlayer.requestInstalledAddons(response -> {
+ List installedAddons = response.getInstalledAddons();
+ // Handle the response
+ });
+ ```
+
+### Via the LabyModProtocol
+
+=== ":octicons-file-code-16: #sendPacket(UUID, Packet)"
+
+ ```java
+ // Create or get a List of addons to request (array is also possible)
+ List addonsToRequest = new ArrayList<>();
+
+ // Add the namespace of all addons that you want to request
+ // Keeping the List empty requests all addons (not recommended)
+ addonsToRequest.add("voicechat");
+
+ // Get the LabyModProtocol
+ LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol();
+
+ // Send the packet
+ labyModProtocol.sendPacket(uniqueId, new InstalledAddonsRequestPacket(addonsToRequest));
+
+ // To handle the response, you need to register a PacketHandler for the
+ // InstalledAddonsResponsePacket yourself!
+ ```
+
+=== ":octicons-file-code-16: #sendPacket(UUID, IdentifiablePacket, Class, Predicate)"
+
+ ```java
+ // Create or get a List of addons to request (array is also possible)
+ List addonsToRequest = new ArrayList<>();
+
+ // Add the namespace of all addons that you want to request
+ // Keeping the List empty requests all addons (not recommended)
+ addonsToRequest.add("voicechat");
+
+ // Get the LabyModProtocol
+ LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol();
+
+ // Send the packet and handle the response
+ labyModProtocol.sendPacket(
+ uniqueId,
+ new InstalledAddonsRequestPacket(recommendations),
+ InstalledAddonsResponsePacket.class,
+ response -> {
+ List installedAddons = response.getInstalledAddons();
+ // Handle the response
+
+ return false; // return false because no other response is expected
+ }
+ );
+ ```
diff --git a/docs/pages/server/labymod/overview.md b/docs/pages/server/labymod/overview.md
index f0e9778..caf83f7 100644
--- a/docs/pages/server/labymod/overview.md
+++ b/docs/pages/server/labymod/overview.md
@@ -18,6 +18,8 @@ The following features are currently available in the LabyMod Protocol:
## Moderation
- [Addon Recommendations](/pages/server/labymod/moderation/addon-recommendation)
+- [Get the Installed Addons](/pages/server/labymod/moderation/installed-addons)
+- [Disable Addons](/pages/server/labymod/moderation/disable-addons)
- [Get the LabyMod Version](/pages/server/labymod/moderation/labymod-version)
- [Permissions](/pages/server/labymod/moderation/permissions)
@@ -30,8 +32,6 @@ The following features are currently available in the LabyMod Protocol:
These features are planned for the future but are not yet available:
-- Getting a Player's Installed Addons
-- Disabling Addons Server-Side
- Sending Notifications
You have a feature request? Feel free to [create an issue on GitHub](https://github.com/LabyMod/labymod4-server-api/issues/new/choose) or post it on [our Discord for Developers](https://labymod.net/dc/dev).
\ No newline at end of file
diff --git a/mkdocs.yml b/mkdocs.yml
index 815f287..4674cbf 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -32,12 +32,15 @@ nav:
- Markers: pages/server/labymod/features/markers.md
- Moderation:
- Addon Recommendations: pages/server/labymod/moderation/addon-recommendation.md
+ - Get Installed Addons: pages/server/labymod/moderation/installed-addons.md
+ - Disable Addons: pages/server/labymod/moderation/disable-addons.md
- Get LabyMod Version: pages/server/labymod/moderation/labymod-version.md
- Permissions: pages/server/labymod/moderation/permissions.md
- Minecraft Supplements:
- Input Prompt: pages/server/labymod/supplements/input-prompt.md
- Server Switch Prompt: pages/server/labymod/supplements/server-switch.md
- Addon Integrations:
+ - BetterPerspective: pages/server/addons/betterperspective/index.md
- VoiceChat:
- Overview: pages/server/addons/voicechat/index.md
- Mute Players: pages/server/addons/voicechat/mute.md