diff --git a/README.md b/README.md index 933ad95..b3afdcb 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,7 @@ This is the official wiki for the LabyMod 4 API. -At the moment, we've only got a wiki for the Addon API but there will be more to come. - Have you found something missing from this wiki that you think is important, or are you unhappy with something? Please fork this repository, add/improve it and create a pull request. -The live build can be found here. +The live build can be found here. diff --git a/docs/assets/files/serverapi/economy_display.gif b/docs/assets/files/serverapi/economy_display.gif new file mode 100644 index 0000000..506b220 Binary files /dev/null and b/docs/assets/files/serverapi/economy_display.gif differ diff --git a/docs/assets/files/serverapi/game-mode.png b/docs/assets/files/serverapi/game-mode.png new file mode 100644 index 0000000..6c88fd6 Binary files /dev/null and b/docs/assets/files/serverapi/game-mode.png differ diff --git a/docs/assets/files/serverapi/input-prompt.png b/docs/assets/files/serverapi/input-prompt.png new file mode 100644 index 0000000..8247a7c Binary files /dev/null and b/docs/assets/files/serverapi/input-prompt.png differ diff --git a/docs/assets/files/serverapi/interaction-menu.png b/docs/assets/files/serverapi/interaction-menu.png new file mode 100644 index 0000000..4c6f030 Binary files /dev/null and b/docs/assets/files/serverapi/interaction-menu.png differ diff --git a/docs/assets/files/serverapi/server-switch-prompt.png b/docs/assets/files/serverapi/server-switch-prompt.png new file mode 100644 index 0000000..11ffa0f Binary files /dev/null and b/docs/assets/files/serverapi/server-switch-prompt.png differ diff --git a/docs/assets/files/serverapi/tablist-banner.png b/docs/assets/files/serverapi/tablist-banner.png new file mode 100644 index 0000000..ae90007 Binary files /dev/null and b/docs/assets/files/serverapi/tablist-banner.png differ diff --git a/docs/assets/theme/js/script.js b/docs/assets/theme/js/script.js deleted file mode 100644 index b3b90f6..0000000 --- a/docs/assets/theme/js/script.js +++ /dev/null @@ -1,31 +0,0 @@ -addCopyright(); -//expandNavigation(); - -function addCopyright() { - let year = new Date().getFullYear(); - - let copyrightElement = document.getElementsByClassName("md-copyright")[0]; - copyrightElement.innerHTML = ""; - - let copyrightText = document.createElement("span"); - copyrightText.innerHTML = "Copyright © " + year; - copyrightElement.appendChild(copyrightText); - - let space = document.createElement("span"); - space.innerHTML = " "; - copyrightElement.appendChild(space); - - let companyLink = document.createElement("a"); - companyLink.href = "https://labymod.net"; - companyLink.innerHTML = "LabyMedia GmbH"; - copyrightElement.appendChild(companyLink); - - let space2 = document.createElement("span"); - space2.innerHTML = " - "; - copyrightElement.appendChild(space2); - - let imprintLink = document.createElement("a"); - imprintLink.href = "https://labymod.net/impressum"; - imprintLink.innerHTML = "Imprint"; - copyrightElement.appendChild(imprintLink); -} \ No newline at end of file diff --git a/docs/pages/addon/contributors.md b/docs/contributors.md similarity index 89% rename from docs/pages/addon/contributors.md rename to docs/contributors.md index 7438e4a..95643b1 100644 --- a/docs/pages/addon/contributors.md +++ b/docs/contributors.md @@ -1,4 +1,4 @@ -Due to the sheer complexity and scope of LabyMod 4 and its addon API, we cannot maintain this wiki alone.
+Due to the sheer complexity and scope of LabyMod 4 and its Addon & Server API, we cannot maintain this wiki alone.
Therefore, we rely on the help of the community to keep this wiki complete and up to date. If you want to help us, feel free to fork the repository of this wiki, make your desired changes and create a pull request here. diff --git a/docs/index.md b/docs/index.md index f3d3239..5703dd8 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,7 +1,12 @@ -# LabyMod4 API Wiki +# LabyMod 4 Developer Portal -Click here to get to the wiki of our new addon API. +Welcome to the Developer Portal of LabyMod 4.
+This website serves as a hub for everything related to the LabyMod 4, directed at developers. Whether you're looking for +information on how to create addons or utilize our server API, you'll find it here. Have you found something missing from this wiki that you think is important, or are you unhappy with something? -Please fork our wiki repository, add/improve it and create a pull request -here. \ No newline at end of file +Please fork our wiki repository, add/improve it and create a pull request +here. + +If you have any questions or need help, feel free to join +our [Discord server for Developers](https://discord.gg/labymod). \ No newline at end of file diff --git a/docs/pages/server/addons/voicechat/index.md b/docs/pages/server/addons/voicechat/index.md new file mode 100644 index 0000000..dbd1614 --- /dev/null +++ b/docs/pages/server/addons/voicechat/index.md @@ -0,0 +1,38 @@ +The VoiceChat integration provides a way to manage the voice chat server-side. + +## Adding the Dependency + +The VoiceChat integration is shipped with all official [server platform integration artifacts](http://localhost:8080/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:voicechat:VERSION") + } + ``` + +=== ":octicons-file-code-16: Gradle (Groovy)" + + ```groovy + dependencies { + compileOnly "net.labymod.serverapi.integration:voicechat:VERSION" + } + ``` + +=== ":octicons-file-code-16: Maven" + + ```xml + + + net.labymod.serverapi.integration + voicechat + VERSION + + + ``` + diff --git a/docs/pages/server/addons/voicechat/mute.md b/docs/pages/server/addons/voicechat/mute.md new file mode 100644 index 0000000..e5468cb --- /dev/null +++ b/docs/pages/server/addons/voicechat/mute.md @@ -0,0 +1,88 @@ +The `VoiceChatMutePacket` is a client-bound packet provided by the VoiceChat integration, that allows servers to mute any player in the voice chat on their server. + +## Creating the Mute Model + +The packet uses the `VoiceChatMute` model, which can be created with `VoiceChatMute.create`. + +```java +// Create the mute model +// For a permanent mute, remove the timestamp parameter +VoiceChatMute voiceChatMute = VoiceChatMute.create( + uniqueId, // The UUID of the player to mute + "Example Mute Reason", // The reason for the mute. Can be null + System.currentTimeMillis() + 60000 // The timestamp until the mute expires. +); +``` + +## Sending the Packet + +The packet can either be sent via the `VoiceChatPlayer` or the `AddonProtocol` of the `VoiceChatIntegration` + +If you are using the `VoiceChatPlayer` to mute a player, the mute will automatically be sent to every LabyMod player on +the server. LabyMod players connecting to the server will also be sent every mute that is currently active automatically. + +### Via VoiceChatPlayer (Recommended) + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Get the VoiceChatPlayer +VoiceChatPlayer voiceChatPlayer = labyModPlayer.getIntegrationPlayer(VoiceChatPlayer.class); + +// Mute the player +voiceChatPlayer.mute(voiceChatMute); +``` + +### Via the AddonProtocol + +While not recommended, it is also possible to send the mutes directly via the `AddonProtocol` of the `VoiceChatIntegration`. + +???+ danger "Important Note" + + When sending mutes directly via the `AddonProtocol` of the `VoiceChatIntegration`, you will have to store all mutes yourself and send them to every player manually. + +```java +// Create or get a List of mutes (array is also possible) +List mutes = new ArrayList<>(); + +// Add all mutes that you want to send to the player +mutes.add(voiceChatMute); + +// Get the VoiceChatIntegration +// #getOrRegisterIntegration is a fail-safe method to get the integration, even +// if the integration has not been registered. Alternatively, you can use +// #getIntegration, which will return null if the integration has not been registered. +VoiceChatIntegration voiceChatIntegration = LabyModProtocolService.get().getOrRegisterIntegration( + VoiceChatIntegration.class, + VoiceChatIntegration::new +); + +// Get the AddonProtocol +AddonProtocol addonProtocol = voiceChatIntegration.voiceChatProtocol(); + +// Send the packet +addonProtocol.sendPacket(uniqueId, new VoiceChatMutePacket(mutes)); +``` + +### Via the LabyMod Player + +While not recommended, it is also possible to send the packet directly via the `LabyModPlayer`. This will basically skip the "protocol-getting" process, as it will search for the protocol automatically. + +???+ danger "Important Note" + + When sending mutes directly via the `LabyModPlayer`, you will have to store all mutes yourself and send them to every player manually. + +```java +// Create or get a List of mutes (array is also possible) +List mutes = new ArrayList<>(); + +// Add all mutes that you want to send to the player +mutes.add(voiceChatMute); + +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Send the packet +labyModPlayer.sendPacket(new VoiceChatMutePacket(mutes)); +``` \ No newline at end of file diff --git a/docs/pages/server/addons/voicechat/open-channels.md b/docs/pages/server/addons/voicechat/open-channels.md new file mode 100644 index 0000000..491f1f1 --- /dev/null +++ b/docs/pages/server/addons/voicechat/open-channels.md @@ -0,0 +1,49 @@ +The `VoiceChatOpenChannelsPacket` is a client-bound packet provided by the VoiceChat integration, that allows servers to open the voice channels popup. + +## Sending the Packet + +The packet can either be sent via the `VoiceChatPlayer` or the `AddonProtocol` of the `VoiceChatIntegration` + +### Via VoiceChatPlayer + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Get the VoiceChatPlayer +VoiceChatPlayer voiceChatPlayer = labyModPlayer.getIntegrationPlayer(VoiceChatPlayer.class); + +// Mute the player +voiceChatPlayer.openVoiceChatChannels(); +``` + +### Via the AddonProtocol + +```java +// Get the VoiceChatIntegration +// #getOrRegisterIntegration is a fail-safe method to get the integration, even +// if the integration has not been registered. Alternatively, you can use +// #getIntegration, which will return null if the integration has not been registered. +VoiceChatIntegration voiceChatIntegration = LabyModProtocolService.get().getOrRegisterIntegration( + VoiceChatIntegration.class, + VoiceChatIntegration::new +); + +// Get the AddonProtocol +AddonProtocol addonProtocol = voiceChatIntegration.voiceChatProtocol(); + +// Send the packet +addonProtocol.sendPacket(uniqueId, new VoiceChatOpenChannelsPacket()); +``` + +### Via the LabyMod Player + +While not recommended, it is also possible to send the packet directly via the `LabyModPlayer`. This will basically skip the "protocol-getting" process, as it will search for the protocol automatically.
+ +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Send the packet +labyModPlayer.sendPacket(new VoiceChatOpenChannelsPacket()); +``` \ No newline at end of file diff --git a/docs/pages/server/addons/voicechat/unmute.md b/docs/pages/server/addons/voicechat/unmute.md new file mode 100644 index 0000000..edf223c --- /dev/null +++ b/docs/pages/server/addons/voicechat/unmute.md @@ -0,0 +1,62 @@ +The `VoiceChatUnmutePacket` is a client-bound packet provided by the VoiceChat integration, that allows servers to remove the server-bound mute from a player in the voice chat. + +## Sending the Packet + +The packet can either be sent via the `VoiceChatPlayer` or the `AddonProtocol` of the `VoiceChatIntegration` + +If you are using the `VoiceChatPlayer` to unmute a player, the unmute will automatically be sent to every LabyMod player on +the server. + +### Via VoiceChatPlayer (Recommended) + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Get the VoiceChatPlayer +VoiceChatPlayer voiceChatPlayer = labyModPlayer.getIntegrationPlayer(VoiceChatPlayer.class); + +// Mute the player +voiceChatPlayer.unmute(); +``` + +### Via the AddonProtocol + +While not recommended, it is also possible to send the unmutes directly via the `AddonProtocol` of the `VoiceChatIntegration`. + +???+ danger "Important Note" + + When sending (un)mutes directly via the `AddonProtocol` of the `VoiceChatIntegration`, you will have to store all mutes yourself and send them to every player manually. + +```java +// Get the VoiceChatIntegration +// #getOrRegisterIntegration is a fail-safe method to get the integration, even +// if the integration has not been registered. Alternatively, you can use +// #getIntegration, which will return null if the integration has not been registered. +VoiceChatIntegration voiceChatIntegration = LabyModProtocolService.get().getOrRegisterIntegration( + VoiceChatIntegration.class, + VoiceChatIntegration::new +); + +// Get the AddonProtocol +AddonProtocol addonProtocol = voiceChatIntegration.voiceChatProtocol(); + +// Send the packet +addonProtocol.sendPacket(uniqueId, new VoiceChatUnmutePacket(uniqueId)); +``` + +### Via the LabyMod Player + +While not recommended, it is also possible to send the packet directly via the `LabyModPlayer`. This will basically skip the "protocol-getting" process, as it will search for the protocol automatically. + +???+ danger "Important Note" + + When sending (un)mutes directly via the `LabyModPlayer`, you will have to store all mutes yourself and send them to every player manually. + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Send the packet +labyModPlayer.sendPacket(new VoiceChatUnmutePacket(uniqueId)); +``` \ No newline at end of file diff --git a/docs/pages/server/index.md b/docs/pages/server/index.md new file mode 100644 index 0000000..70d7be5 --- /dev/null +++ b/docs/pages/server/index.md @@ -0,0 +1,173 @@ +???+ danger "Important Note" + + You'll need Java Development Kit (JDK) 17 or higher to be able to use the LabyMod 4 Server API. + +## Adding the LabyMod Repository + +=== ":octicons-file-code-16: Gradle (Kotlin DSL)" + + ```kotlin + repositories { + maven { + name = "labymod" + url = uri("https://dist.labymod.net/api/v1/maven/release/") + } + } + ``` + +=== ":octicons-file-code-16: Gradle (Groovy)" + + ```groovy + repositories { + maven { + name = "labymod" + url = "https://dist.labymod.net/api/v1/maven/release/" + } + } + ``` + +=== ":octicons-file-code-16: Maven" + + ```xml + + + labymod + https://dist.labymod.net/api/v1/maven/release/ + + + ``` + +## Adding the LabyMod 4 Server API as a Dependency + +Depending on the actual artifact you want to use, you have to add the following dependency to your project. Listed below are the available artifacts and their use cases: + +- `api` - The protocol itself without any LabyMod-specific code. Useful if you want to just use the protocol. +- `core` - The LabyMod implementation of the protocol, containing all packets and models to interact with the LabyMod client. Use this if you want to communicate with the LabyMod 4 Server API platform-independently. +- `server-bukkit` - The platform-specific implementation of the LabyMod Protocol for Servers running on Bukkit (Spigot, Paper, etc.). +- `server-bungeecord` - The platform-specific implementation of the LabyMod Protocol for Servers running on BungeeCord. +- `server-velocity` - The platform-specific implementation of the LabyMod Protocol for Servers running on Velocity. +- `server-common` - Contains shared classes and utilities used across different server implementations to ensure consistent behavior and reduce code duplication. Use this if you want to create your own platform implementation. + +???+ danger "Important Note" + + For the examples below, replace `ARTIFACT` and `VERSION` with the artifact and 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?label=%20) + + +=== ":octicons-file-code-16: Gradle (Kotlin DSL)" + + ```kotlin + dependencies { + compileOnly("net.labymod.serverapi:ARTIFACT:VERSION") + } + ``` + +=== ":octicons-file-code-16: Gradle (Groovy)" + + ```groovy + dependencies { + compileOnly "net.labymod.serverapi:ARTIFACT:VERSION" + } + ``` + +=== ":octicons-file-code-16: Maven" + + ```xml + + + net.labymod.serverapi + ARTIFACT + VERSION + + + ``` + +## Setting up Your Plugin + +Each officially supported server platform has two types of implementations. + +1. You load the official jar file into your server's plugins folder and add it as a plugin dependency to your plugin. +2. You shade the dependency into your plugin and initialize it manually, effectively eliminating the need to have the +Server API run as a separate plugin. + +### Bukkit Plugin + +#### Running the Server API as a Plugin + +1. Add the `server-bukkit` dependency to your project's dependencies as described above. +2. Download the latest version of the `server-bukkit` jar file from the GitHub Releases. +3. Place the jar file in your server's `plugins` folder. +4. Add the following line to your plugin's `plugin.yml`: + ```yaml + depend: [LabyModServerAPI] + ``` +5. You're now ready to use the LabyMod 4 Server API in your Bukkit plugin. + +#### Shading the Server API into Your Plugin + +1. Add the `server-bukkit` dependency to your project's dependencies as described above. +2. Configure shadow in your project's `build.gradle` or `pom.xml` to shade the `server-bukkit` dependency into your plugin. +3. Initialize the LabyMod 4 Server API in your plugin's `onEnable` method: + ```java + @Override + public void onEnable() { + LabyModProtocolService.initialize(this); + } + ``` +4. You're now ready to use the LabyMod 4 Server API in your Bukkit plugin. + +### BungeeCord Plugin + +#### Running the Server API as a Plugin + +1. Add the `server-bungeecord` dependency to your project's dependencies as described above. +2. Download the latest version of the `server-bungeecord` jar file from the GitHub Releases. +3. Place the jar file in your server's `plugins` folder. +4. Add the following line to your plugin's `plugin.yml` or `bungee.yml`: + ```yaml + depend: [LabyModServerAPI] + ``` +5. You're now ready to use the LabyMod 4 Server API in your BungeeCord plugin. + +#### Shading the Server API into Your Plugin + +1. Add the `server-bungeecord` dependency to your project's dependencies as described above. +2. Configure shadow in your project's `build.gradle` or `pom.xml` to shade the `server-bungeecord` dependency into your plugin. +3. Initialize the LabyMod 4 Server API in your plugin's `onEnable` method: + ```java + @Override + public void onEnable() { + LabyModProtocolService.initialize(this); + } + ``` +4. You're now ready to use the LabyMod 4 Server API in your BungeeCord plugin. + +### Velocity Plugin + +#### Running the Server API as a Plugin + +1. Add the `server-velocity` dependency to your project's dependencies as described above. +2. Download the latest version of the `server-velocity` jar file from the GitHub Releases. +3. Place the jar file in your server's `plugins` folder. +4. Add the following code to the `Plugin` annotation above your plugin's main class: + ```java + dependencies = { + @Dependency(id = "labymod-server-api") + } + ``` +5. You're now ready to use the LabyMod 4 Server API in your BungeeCord plugin. + +#### Shading the Server API into Your Plugin + +1. Add the `server-velocity` dependency to your project's dependencies as described above. +2. Configure shadow in your project's `build.gradle` or `pom.xml` to shade the `server-velocity` dependency into your plugin. +3. Initialize the LabyMod 4 Server API in your plugin's `ProxyInitializeEvent` listener: + ```java + @Override + public void onEnable() { + LabyModProtocolService.initialize(this, this.server, this.logger); + } + ``` +4. You're now ready to use the LabyMod 4 Server API in your Velocity plugin. + + + diff --git a/docs/pages/server/integrations.md b/docs/pages/server/integrations.md new file mode 100644 index 0000000..7676f2f --- /dev/null +++ b/docs/pages/server/integrations.md @@ -0,0 +1,96 @@ +Integrations are an integral part of the LabyMod 4 Server API. They provide a way to extend the server API with +additional features and functionalities. Integrations can be used to interact with LabyMod addons seamlessly. + +## Official Integrations + +We provide official integrations for addons developed by LabyMod utilizing the Server API. Their source code is +available on [GitHub](https://github.com/LabyMod/labymod4-server-api-integrations). + +## Create an Integration + +Integrations are created on the abstract layer of the Server API to support both server and client-side with the same +artifact.
+ +### Create the Class + +Create a class that implements the interface `LabyModProtocolIntegration`. +The interface provides two methods, `initialize(AbstractLabyModProtocolService)` and +`createIntegrationPlayer(AbstractLabyModPlayer)`. `initialize` is called when the integration is loaded and +implementing this is required. `createIntegrationPlayer` is called when a LabyMod player connects to the server and +implementing it is optional. + +```java +import net.labymod.serverapi.core.AbstractLabyModProtocolService; +import net.labymod.serverapi.core.integration.LabyModProtocolIntegration; + +public class ExampleIntegration implements LabyModProtocolIntegration { + + private AbstractLabyModProtocolService protocolService; + + @Override + public void initialize(AbstractLabyModProtocolService protocolService) { + // Check if the field is already set, if so throw an exception. This is a good practice to + // prevent the integration from being initialized multiple times. + if (this.protocolService != null) { + throw new IllegalStateException("VoiceChatIntegration is already initialized"); + } + + // Store the protocol service for later use + this.protocolService = protocolService; + } +} +``` + +### Registering the Service + +While not required if you are using the Integration by calling `LabyModProtocolService#getOrRegisterIntegration` ( +because the integration would be registered if not already), it is recommended to register the Integration as a service +to automate the registering this process. + +#### Registering via AutoService + +To register the integration via AutoService, you first need to add the dependency to your project. + +=== ":octicons-file-code-16: Gradle (Kotlin DSL)" + + ```kotlin + dependencies { + compileOnly("com.google.auto.service:auto-service:1.1.1") + annotationProcessor("com.google.auto.service:auto-service:1.1.1") + } + ``` + +=== ":octicons-file-code-16: Gradle (Groovy)" + + ```groovy + dependencies { + compileOnly "com.google.auto.service:auto-service:1.1.1" + annotationProcessor "com.google.auto.service:auto-service:1.1.1" + } + ``` + +=== ":octicons-file-code-16: Maven" + + ```xml + + + com.google.auto.service + auto-service + 1.1.1 + true + + + ``` + +After adding the dependency, you can annotate your integration class with `@AutoService(LabyModProtocolIntegration.class)`. + +#### Registering Manually + +To register the integration manually, create the directory `META-INF/services` in your resources folder and create a +file named `net.labymod.serverapi.core.integration.LabyModProtocolIntegration` with the fully qualified name (package + +class name) of your integration class. + +### Creating a Protocol + +To create a custom protocol, you can create a new instance of `AddonProtocol` in the `initialize` method of your integration.
+Take a look at [Create a Custom Protocol](/pages/server/protocols/#create-a-custom-protocol) or the [official VoiceChat integration on GitHub](https://github.com/LabyMod/labymod4-server-api-integrations/blob/master/voicechat/src/main/java/net/labymod/serverapi/integration/voicechat/VoiceChatIntegration.java) for an example. diff --git a/docs/pages/server/labymod/displays/economy.md b/docs/pages/server/labymod/displays/economy.md new file mode 100644 index 0000000..1c3709c --- /dev/null +++ b/docs/pages/server/labymod/displays/economy.md @@ -0,0 +1,131 @@ +The `EconomyDisplayPacket` is a client-bound packet that allows servers to display balance information of multiple +virtual currencies in the HUD of the LabyMod player. + +![Example Economy Display](/assets/files/serverapi/economy_display.gif) + +## The Economy Display Model + +There are several constructors available in the `EconomyDisplay` class. If you're managing the Economy Displays with the +LabyModPlayer object, you won't need to create the model yourself. + +The following methods are available to update the values of an Economy Display: + +- `#balance(double)` - Updates the balance of the economy. Default is `0`. +- `#visible(boolean)` - Updates the visibility state of the economy. Default is `true`. +- `#iconUrl(String)` - Allows you to update the icon of the economy. Default is `null`. +- `#decimalFormat(DecimalFormat)` - Allows you to update the format and divisor of the economy. + +???+ note + + When sending an custom Economy Display (meaning that the key is neither `bank` nor `cash`) to the player and no icon url is set, the default icon of the cash economy will be used. + +## Managing via LabyModPlayer (Recommended) + +The `LabyModPlayer` class provides a range of methods to manage the economy displays. + +### Get an Economy Display + +All economy displays updated or sent with either the update or send method will be stored in the `LabyModPlayer` +object.
+Economies sent outside the LabyModPlayer object cannot be accessed via the methods below. + +=== ":fontawesome-solid-building-columns: Bank Economy" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Get the Bank Economy Display + EconomyDisplay bankEconomy = labyModPlayer.bankEconomy(); + ``` + +=== ":fontawesome-solid-money-bill: Cash Economy" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Get the Cash Economy Display + EconomyDisplay cashEconomy = labyModPlayer.cashEconomy(); + ``` + +=== ":fontawesome-solid-dollar-sign: Custom Economy" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Get the Custom Economy Display. Replace "custom" with the key of your custom + // economy + EconomyDisplay customEconomy = labyModPlayer.getEconomy("custom"); // Nullable! + ``` + +### Update an Economy Display + +You can directly update the economy stored in the `LabyModPlayer` object and send it to the player. + +Methods to update the economy display's values are shown in the [Economy Display Model](#the-economy-display-model). + +=== ":fontawesome-solid-building-columns: Bank Economy" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Update the Bank Economy Display + labyModPlayer.updateBankEconomy(economy -> { + // Update the values of the economy + }); + ``` + +=== ":fontawesome-solid-money-bill: Cash Economy" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Update the Cash Economy Display + labyModPlayer.updateCashEconomy(economy -> { + // Update the values of the economy + }); + ``` + +=== ":fontawesome-solid-dollar-sign: Custom Economy" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Update the Custom Economy Display. Replace "custom" with the key of your + // custom economy + labyModPlayer.updateEconomy("custom", economy -> { + // Update the values of the economy + }); + ``` + +### Send an Economy Display + +When updating an economy, you can either use [Update an Economy Display](#update-an-economy-display) or the following +method to store and send it +to the player. + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Store and Send the Economy Display +labyModPlayer.sendEconomy(economyDisplay); +``` + +## Sending via the LabyModProtocol + +While not recommended, it is also possible to send the economy displays directly via the `LabyModProtocol`.
+But keep in mind, that you have to store the economies yourself if you want to update them later. + +```java +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new EconomyDisplayPacket(economyDisplay)); +``` diff --git a/docs/pages/server/labymod/displays/subtitles.md b/docs/pages/server/labymod/displays/subtitles.md new file mode 100644 index 0000000..244809e --- /dev/null +++ b/docs/pages/server/labymod/displays/subtitles.md @@ -0,0 +1,79 @@ +The `SubtitlePacket` is a client-bound packet that allows servers to display a subtitle to the player. The subtitle is +displayed below the player's name tag. + +## The Subtitle Model + +The `Subtitle` class provides several factory methods. If you're managing the Subtitles with the `LabyModPlayer` object, +you won't need to create the model yourself. + +The following methods are available to update the values of an Economy Display: + +- `#text(ServerAPIComponent)` - Updates the text of the subtitle. Default is `null`. +- `#size(double)` - Updates the size of the subtitle. Default is `1`. + +## Managing via LabyModPlayer (Recommended) + +The `LabyModPlayer` class provides a range of methods to manage the subtitles. + +Additionally, if you use the methods below, subtitles are automatically sent to every other LabyMod player on the +server. LabyMod players connecting to the server will also be sent every subtitle that is currently active +automatically. + +### Updating the Subtitle + +Updating the subtitle allows you to change the text and size of the subtitle. If no subtitle was set before, a new +one will be created. + +=== ":fontawesome-solid-pen-to-square: Update Text" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Update the Subtitle text + labyModPlayer.updateSubtitle(ServerAPIComponent.text("Example Subtitle")); + ``` + +=== ":fontawesome-solid-pen-to-square: Update Text and Size" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Update the Subtitle text and size + labyModPlayer.updateSubtitle(ServerAPIComponent.text("Example Subtitle"), 0.5D); + ``` + +### Reset the Subtitle + +Resetting the subtitle will remove the subtitle from the player. + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Reset the subtitle +labyModPlayer.resetSubtitle(); +``` + +## Sending via the LabyModProtocol + +While not recommended, it is also possible to send the subtitles directly via the `LabyModProtocol`. + +???+ danger "Important Note" + + When sending subtitles directly via the `LabyModProtocol`, you will have to store all subtitles yourself and send them to every player manually. + +```java +// Create or get a List of subtitles (array is also possible) +List subtitles = new ArrayList<>(); + +// Add all subtitles you want to send to the player +subtitles.add(Subtitle.create(uniqueId, ServerAPIComponent.text("Example Subtitle"))); + +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new SubtitlePacket(subtitles)); +``` diff --git a/docs/pages/server/labymod/displays/tablist-banner.md b/docs/pages/server/labymod/displays/tablist-banner.md new file mode 100644 index 0000000..0f62e6e --- /dev/null +++ b/docs/pages/server/labymod/displays/tablist-banner.md @@ -0,0 +1,33 @@ +The `TabListBannerPacket` is a client-bound packet that allows servers to add a custom banner above the player list. + +???+ warning "Important Note" + + The aspect ratio of the image must be `5:1` and the recommended resolution is `1280x256` pixels. + +![TabList Banner](/assets/files/serverapi/tablist-banner.png) + +## Sending the Packet + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +The value can either be a URL to the image or `null` to unset the banner. + +### Via LabyModPlayer + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Send the tab list banner +labyModPlayer.sendTabListBanner("https://example.com/banner.png"); +``` + +### Via the LabyModProtocol + +```java +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new TabListBannerPacket("https://example.com/banner.png")); +``` diff --git a/docs/pages/server/labymod/displays/tablist-flags.md b/docs/pages/server/labymod/displays/tablist-flags.md new file mode 100644 index 0000000..61f6e3d --- /dev/null +++ b/docs/pages/server/labymod/displays/tablist-flags.md @@ -0,0 +1,39 @@ +The `TabListFlagPacket` is a client-bound packet that allows servers to display a flag in the tab list next to the player's name. + +## Managing via LabyModPlayer (Recommended) + +The `LabyModPlayer` class provides a method to manage the tab list flags. + +Additionally, if you use the method below, flags are automatically sent to every LabyMod player on the +server. LabyMod players connecting to the server will also be sent every flag that is currently active +automatically. + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Set the country code of the flag +labyModPlayer.setTabListFlag(TabListFlagCountryCode.DE); +``` + +## Sending via the LabyModProtocol + +While not recommended, it is also possible to send the flags directly via the `LabyModProtocol`. + +???+ danger "Important Note" + + When sending flags directly via the `LabyModProtocol`, you will have to store all flags yourself and send them to every player manually. + +```java +// Create or get a List of flags (array is also possible) +List flags = new ArrayList<>(); + +// Add all flags you want to send to the player +flags.add(TabListFlag.create(uniqueId, TabListFlagCountryCode.DE)); + +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new TabListFlagPacket(flags)); +``` diff --git a/docs/pages/server/labymod/features/discord.md b/docs/pages/server/labymod/features/discord.md new file mode 100644 index 0000000..8098261 --- /dev/null +++ b/docs/pages/server/labymod/features/discord.md @@ -0,0 +1,55 @@ +The `DiscordRPCPacket` is a client-bound packet that allows servers to customize the Discord Rich Presence of their players. + +## Creating a Discord Rich Presence + +### With Game Mode + +Create the model with `DiscordRichPresence.create` to create a Discord Rich Presence with the current game mode. +```java +DiscordRPC discordRPC = DiscordRPC.create("Example Game Mode"); +``` + +### With Game Mode and Start Time + +Create the model with `DiscordRichPresence.createWithStart` to create a Discord Rich Presence with the current game mode and the start time. +```java +DiscordRPC discordRPC = DiscordRPC.createWithStart("Example Game Mode", System.currentTimeMillis()); +``` + +### With Game Mode and End Time + +Create the model with `DiscordRichPresence.createWithEnd` to create a Discord Rich Presence with the current game mode and the end time. +```java +DiscordRPC discordRPC = DiscordRPC.createWithEnd("Example Game Mode", System.currentTimeMillis()); +``` + +### Reset to Default + +Create the model with `DiscordRichPresence.reset` to reset the Discord Rich Presence to the default state. +```java +DiscordRPC discordRPC = DiscordRPC.createReset(); +``` + +## Sending the Packet + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +### Via LabyModPlayer + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Send the discord rpc model +labyModPlayer.sendDiscordRPC(discordRPC); +``` + +### Via the LabyModProtocol + +```java +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new DiscordRPCPacket(discordRPC)); +``` \ No newline at end of file diff --git a/docs/pages/server/labymod/features/emotes.md b/docs/pages/server/labymod/features/emotes.md new file mode 100644 index 0000000..f62629c --- /dev/null +++ b/docs/pages/server/labymod/features/emotes.md @@ -0,0 +1,80 @@ +The `EmotePacket` is a client-bound packet that allows servers to let NPCs perform emotes. + +???+ warning "Important Note" + + To prevent abuse, this does not work for real players. You can only perform emotes on players that have the second half of their UUID entirely being 0 (-> 64 least significant bits are 0, or the second long value equals 0).
You therefore need to spawn them with a uuid like this. + +## Creating the Emote Model + +The packet uses the `Emote` model. + +### Play an Emote + +Create the model with `Emote.play(UUID, int)` to create an emote with the unique id of the npc and the id of the emote to perform. +```java +Emote emote = Emote.play(npcUniqueId, 2); +``` + +### Stop an Emote + +Create the model with `Emote.stop(UUID)` to stop the current emote of the npc. +```java +Emote emote = Emote.stop(npcUniqueId); +``` + +## Sending the Packet + +```java +// Create a List of emotes (array is also possible) +List emotes = new ArrayList<>(); + +// Add all emotes you want to perform +emotes.add(emote); + +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new EmotePacket(emotes)); +``` + +## Available Emotes + +The following emotes are available: + + \ No newline at end of file diff --git a/docs/pages/server/labymod/features/gamemode.md b/docs/pages/server/labymod/features/gamemode.md new file mode 100644 index 0000000..016c463 --- /dev/null +++ b/docs/pages/server/labymod/features/gamemode.md @@ -0,0 +1,32 @@ +The `PlayingGameModePacket` is a client-bound packet that sends the current game mode to the player's LabyMod Chat friends. + +![Example Playing Game Mode](/assets/files/serverapi/game-mode.png) + +## Sending the Packet + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +The value can be a string that represents the current game mode, or `null` to unset the current game mode. + +### Via LabyModPlayer + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Send the game mode +labyModPlayer.sendPlayingGameMode("Example Game Mode"); +``` + +### Via the LabyModProtocol + +```java +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket( + uniqueId, + new PlayingGameModePacket("Example Game Mode") +); +``` diff --git a/docs/pages/server/labymod/features/interaction-menu.md b/docs/pages/server/labymod/features/interaction-menu.md new file mode 100644 index 0000000..bf480eb --- /dev/null +++ b/docs/pages/server/labymod/features/interaction-menu.md @@ -0,0 +1,67 @@ +The `InteractionMenuPacket` is a client-bound packet that allows servers to add custom interaction menu entries. + +![Example Interaction Menu Entry](/assets/files/serverapi/interaction-menu.png) + +## Creating an Interaction Menu Entry + +The packet uses the `InteractionMenuEntry` model, which can be created with `InteractionMenuEntry.create`. +The InteractionMenuEntry model uses the Server API's own Component model. + +### Actions +There are four different types of actions an interaction menu entry can perform: + +- `InteractionMenuType.RUN_COMMAND` - Executes the value as command. +- `InteractionMenuType.CLIPBOARD` - Copies the value to the clipboard. +- `InteractionMenuType.SUGGEST_COMMAND` - Opens the chat and suggests the value. +- `InteractionMenuType.OPEN_BROWSER` - Opens the web browser with the value as URL. + +### Value Placeholders +The value can contain the following placeholders (addons may add custom placeholders): + +- `{name}` - Will be replaced with the player's name. +- `{uuid}` - Will be replaced with the player's unique id. + +### Example +```java +InteractionMenuEntry exampleEntry = InteractionMenuEntry.create( + ServerAPIComponent.text("Example Entry").color(ServerAPITextColor.YELLOW), + InteractionMenuEntry.InteractionMenuType.RUN_COMMAND, + "/example" +); +``` + +## Sending the Packet + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +### Via LabyModPlayer + +```java +// Create a List of entries (array is also possible) +List entries = new ArrayList<>(); + +// Add all entries that you want to display +entries.add(exampleEntry); + +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Send the entries +labyModPlayer.sendInteractionMenuEntries(entries); +``` + +### Via the LabyModProtocol + +```java +// Create a List of entries (array is also possible) +List entries = new ArrayList<>(); + +// Add all entries that you want to display +entries.add(exampleEntry); + +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new InteractionMenuPacket(entries)); +``` diff --git a/docs/pages/server/labymod/features/markers.md b/docs/pages/server/labymod/features/markers.md new file mode 100644 index 0000000..5c1a288 --- /dev/null +++ b/docs/pages/server/labymod/features/markers.md @@ -0,0 +1,87 @@ +Markers are a feature of LabyMod that allows players to place markers on the screen. These markers can be used to highlight certain areas or entities in the game. + +## Set Maker Send Type + +The send type is sent via the `MarkerPacket`. By default, Markers are only sent to LabyMod friends of the player. You can change this behaviour so that markers are sent to the server via the Server API, you then can handle the Marker and possibly forward them to other players. + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +### Via LabyModPlayer + +```java +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Set the marker send type. +// Using MarkerSendType.LABY_CONNECT will restore the default behaviour. +labyModPlayer.sendMarkerSendType(MarkerSendType.SERVER); +``` + +### Via the LabyModProtocol + +```java +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet. +// Using MarkerSendType.LABY_CONNECT will restore the default behaviour. +labyModProtocol.sendPacket(uniqueId, new MarkerPacket(MarkerSendType.SERVER)); +``` + +## Send Markers to the Player + +Markers can be sent to the Player via the `AddMarkerPacket`. + +```java +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new AddMarkerPacket( + uniqueId, // The sender of the marker + 0, // The x coordinate of the marker + 0, // The y coordinate of the marker + 0, // The z coordinate of the marker + true, // Whether the marker should be large or not + null // The target of the marker, can be null +)); +``` + +## Receiving Markers + +To receive markers sent by players, you first need to set the marker send type to `SERVER` as described above. Then you can create a `PacketHandler` for the `ClientAddMarkerPacket` to receive the markers. Registering a `PacketHandler` is described [here](/pages/server/protocols/#registering-handlers). + +To keep the example platform-independent, we removed the import for `LabyModProtocolService`. Make sure to import the class in your implementation. + +```java +import net.labymod.serverapi.api.packet.PacketHandler; +import net.labymod.serverapi.core.LabyModProtocol; +import net.labymod.serverapi.core.packet.clientbound.game.feature.marker.AddMarkerPacket; +import net.labymod.serverapi.core.packet.serverbound.game.feature.marker.ClientAddMarkerPacket; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class ClientAddMarkerPacketHandler implements PacketHandler { + + private final LabyModProtocolService protocolService; + + public ClientAddMarkerPacketHandler(LabyModProtocolService protocolService) { + this.protocolService = protocolService; + } + + @Override + public void handle(@NotNull UUID sender, @NotNull ClientAddMarkerPacket packet) { + // Map the ClientAddMarkerPacket to a AddMarkerPacket + AddMarkerPacket addMarkerPacket = packet.toAddMarkerPacket(sender); + + // Get the LabyModProtocol + LabyModProtocol labyModProtocol = this.protocolService.labyModProtocol(); + + // Loop through all players and send the packet + this.protocolService.forEachPlayer(player -> labyModProtocol.sendPacket( + player.getUniqueId(), addMarkerPacket + )); + } +} +``` \ No newline at end of file diff --git a/docs/pages/server/labymod/moderation/addon-recommendation.md b/docs/pages/server/labymod/moderation/addon-recommendation.md new file mode 100644 index 0000000..620760d --- /dev/null +++ b/docs/pages/server/labymod/moderation/addon-recommendation.md @@ -0,0 +1,113 @@ +The `AddonRecommendationPacket` is a client-bound packet that opens a popup for the player with addons that are recommended or even required. The client will then respond with an `AddonRecommendationResponsePacket` that contains the player's response. + +If you're sending required addons, you'll need to handle the response and check if the player has installed all required addons yourself. LabyMod itself does not enforce the installation of required addons. + +???+ danger "Note" + The `AddonRecommendationResponsePacket` is sent twice by the client. Once before opening the popup and once the player has closed the popup. The `#isInitial` method can be used to check which response is being sent. + +## Creating an Addon Recommendation + +The packet uses the `RecommendedAddon` model, which can be created with `RecommendedAddon.of`. + +```java +// Create the recommended adddon and provide the namespace +RecommendedAddon recommendedAddon = RecommendedAddon.of("example"); + +// If the addon is required, execute the following line +recommendedAddon.require(); +``` + +## Sending the Packet + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +If you're not sending the packet with an integrated handler, you need to register a handler for the `AddonRecommendationResponsePacket` yourself. The process is explained [here](/pages/server/protocols/#registering-handlers). + +### Via LabyModPlayer (Recommended) + +=== ":octicons-file-code-16: #sendAddonRecommendations(List, Consumer)" + + ```java + // Create or get a List of recommended addons + List recommendations = new ArrayList<>(); + + // Add all recommended addons you want to send to the player + recommendations.add(recommendedAddon); + + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Send the recommended addons and handle the response + labyModPlayer.sendAddonRecommendations(recommendations, response -> { + boolean initial = response.isInitial(); // Whether the response is the initial response + boolean allInstalled = response.isAllInstalled(); // Whether all recommended addons are installed + // Directly handle the response + }); + ``` + +=== ":octicons-file-code-16: #sendAddonRecommendations(List)" + + ```java + // Create or get a List of recommended addons + List recommendations = new ArrayList<>(); + + // Add all recommended addons you want to send to the player + recommendations.add(recommendedAddon); + + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Send the recommended addons + labyModPlayer.sendAddonRecommendations(serverSwitchPrompt); + + // To handle the response, you need to register a PacketHandler for the + // AddonRecommendationResponsePacket yourself! + ``` + +### Via the LabyModProtocol + +=== ":octicons-file-code-16: #sendPacket(UUID, Packet)" + + ```java + // Create or get a List of recommended addons (array is also possible) + List recommendations = new ArrayList<>(); + + // Add all recommended addons you want to send to the player + recommendations.add(recommendedAddon); + + // Get the LabyModProtocol + LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + + // Send the packet + labyModProtocol.sendPacket(uniqueId, new AddonRecommendationPacket(recommendations)); + + // To handle the response, you need to register a PacketHandler for the + // AddonRecommendationResponsePacket yourself! + ``` + +=== ":octicons-file-code-16: #sendPacket(UUID, IdentifiablePacket, Class, Predicate)" + + ```java + // Create or get a List of recommended addons (array is also possible) + List recommendations = new ArrayList<>(); + + // Add all recommended addons you want to send to the player + recommendations.add(recommendedAddon); + + // Get the LabyModProtocol + LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + + // Send the packet and handle the response + labyModProtocol.sendPacket( + uniqueId, + new AddonRecommendationPacket(recommendations), + AddonRecommendationResponsePacket.class, + response -> { + boolean initial = response.isInitial(); // Whether the response is the initial response + boolean allInstalled = response.isAllInstalled(); // Whether all recommended addons are installed + // Handle the response packet + + return initial; // return #isInitial, as another response is expected if it is the initial response + } + ); + ``` \ No newline at end of file diff --git a/docs/pages/server/labymod/moderation/labymod-version.md b/docs/pages/server/labymod/moderation/labymod-version.md new file mode 100644 index 0000000..e06b0ed --- /dev/null +++ b/docs/pages/server/labymod/moderation/labymod-version.md @@ -0,0 +1,10 @@ +The `VersionLoginPacket` is a server-bound packet that is sent to the server directly after connecting to it. It +contains the player's LabyMod version and serves as the first communication between LabyMod and the server. + +## Receiving the Packet + +There is generally no need to manually handle this packet, as the LabyMod Server API creates the `LabyModPlayer` object +upon receiving this packet. The LabyMod version is then stored in the player's `LabyModPlayer` and can be accessed via +`LabyModPlayer#getLabyModVersion()`. + +If you want to handle it anyway, you can register a `PacketHandler` for the `VersionLoginPacket`. The process is explained [here](/pages/server/protocols/#registering-handlers). \ No newline at end of file diff --git a/docs/pages/server/labymod/moderation/permissions.md b/docs/pages/server/labymod/moderation/permissions.md new file mode 100644 index 0000000..e953363 --- /dev/null +++ b/docs/pages/server/labymod/moderation/permissions.md @@ -0,0 +1,47 @@ +The `PermissionPacket` is a client-bound packet that allows servers to deactivate and/or activate certain features for +their LabyMod players. + +## What permissions are available? + +All permissions available in LabyMod 4 itself can be found as constants in the `Permission` class, integrations may also +create their own permissions.
+Creating custom permissions is possible via `Permission.of(String)`. + +## Sending the Packet + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +The packet requires the type `StatedPermission` which can be obtained by calling either `Permission#allow` or +`Permission#deny`. So for example `Permission.CHAT_AUTOTEXT.deny()` would disable the chat autotext feature. + +### Via LabyModPlayer + +```java +// Create a List of permissions (array is also possible) +List permissions = new ArrayList<>(); + +// Add all permissions you want to allow and/or deny +permissions.add(Permission.CHAT_AUTOTEXT.deny()); + +// Get the LabyModPlayer +LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + +// Send the permissions +labyModPlayer.sendPermissions(permissions); +``` + +### Via the LabyModProtocol + +```java +// Create a List of permissions (array is also possible) +List permissions = new ArrayList<>(); + +// Add all permissions you want to allow and/or deny +permissions.add(Permission.CHAT_AUTOTEXT.deny()); + +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Send the packet +labyModProtocol.sendPacket(uniqueId, new PermissionPacket(permissions)); +``` diff --git a/docs/pages/server/labymod/overview.md b/docs/pages/server/labymod/overview.md new file mode 100644 index 0000000..f0e9778 --- /dev/null +++ b/docs/pages/server/labymod/overview.md @@ -0,0 +1,37 @@ +The following features are currently available in the LabyMod Protocol: + +## Server Displays + +- [Economy Displays](/pages/server/labymod/displays/economy) +- [Subtitles](/pages/server/labymod/displays/subtitles) +- [TabList Server Banner](/pages/server/labymod/displays/tablist-banner) +- [TabList Country Flags](/pages/server/labymod/displays/tablist-flags) + +## Features + +- [Discord Rich Presence](/pages/server/labymod/features/discord) +- [Emote API](/pages/server/labymod/features/emotes) +- [Playing Game Mode](/pages/server/labymod/features/gamemode) +- [Interaction Menu Entries](/pages/server/labymod/features/interaction-menu) +- [Markers](/pages/server/labymod/features/markers) + +## Moderation + +- [Addon Recommendations](/pages/server/labymod/moderation/addon-recommendation) +- [Get the LabyMod Version](/pages/server/labymod/moderation/labymod-version) +- [Permissions](/pages/server/labymod/moderation/permissions) + +## Supplements + +- [Input Prompts](/pages/server/labymod/supplements/input-prompt) +- [Server Switch Prompts](/pages/server/labymod/supplements/server-switch) + +## Planned Features + +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/docs/pages/server/labymod/supplements/input-prompt.md b/docs/pages/server/labymod/supplements/input-prompt.md new file mode 100644 index 0000000..ed618a9 --- /dev/null +++ b/docs/pages/server/labymod/supplements/input-prompt.md @@ -0,0 +1,103 @@ +The `InputPromptPacket` is a client-bound packet that opens a prompt for the player with a text field. + +The client will then respond with a `InputPromptResponsePacket` that contains the player's input. + +![Example Input Prompt](/assets/files/serverapi/input-prompt.png) + +## Creating an Input Prompt + +The packet uses the `InputPrompt` model, which can be created with either `InputPrompt.builder` or `InputPrompt.create`. +The InputPrompt model uses the Server API's own Component model. + +=== ":octicons-file-code-16: InputPrompt.builder" + + ```java + InputPrompt inputPrompt = InputPrompt.builder() + .title(ServerAPIComponent.text("Example Input Switch Prompt") + .color(ServerAPITextColor.AQUA) + .decorate(ServerAPITextDecoration.BOLD)) + .placeholder(ServerAPIComponent.text("Example placeholder")) + .defaultValue("value") + .maxLength(12) + .build(); + ``` + +=== ":octicons-file-code-16: InputPrompt.create" + + ```java + InputPrompt inputPrompt = InputPrompt.create( + ServerAPIComponent.text("Example Input Switch Prompt") + .color(ServerAPITextColor.AQUA) + .decorate(ServerAPITextDecoration.BOLD), + ServerAPIComponent.text("Example placeholder"), + "value", + 12 + ); + ``` + +## Sending the Packet + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +If you're not sending the packet with an integrated handler, you need to register a handler for the `ServerSwitchPromptResponsePacket` yourself. The process is explained [here](/pages/server/protocols/#registering-handlers). + +### Via LabyModPlayer (Recommended) + +=== ":octicons-file-code-16: #openInputPrompt(InputPrompt, Consumer)" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Open the input prompt and handle the response + labyModPlayer.openInputPrompt(inputPrompt, input -> { + // Directly handle the input + }); + ``` + +=== ":octicons-file-code-16: #openInputPrompt(InputPrompt)" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Open the input prompt + labyModPlayer.openInputPrompt(inputPrompt); + + // To handle the response, you need to register a PacketHandler for the + // InputPromptResponsePacket yourself! + ``` + +### Via the LabyModProtocol + +=== ":octicons-file-code-16: #sendPacket(UUID, Packet)" + + ```java + // Get the LabyModProtocol + LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + + // Send the packet + labyModProtocol.sendPacket(uniqueId, new InputPromptPacket(inputPrompt)); + + // To handle the response, you need to register a PacketHandler for the + // InputPromptResponsePacket yourself! + ``` + +=== ":octicons-file-code-16: #sendPacket(UUID, IdentifiablePacket, Class, Predicate)" + + ```java + // Get the LabyModProtocol + LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + + // Send the packet and handle the response + labyModProtocol.sendPacket( + uniqueId, + new InputPromptPacket(inputPrompt), + InputPromptResponsePacket.class, + response -> { + // Handle the response packet + + return false; // Return false, as only one response is expected + } + ); + ``` \ No newline at end of file diff --git a/docs/pages/server/labymod/supplements/server-switch.md b/docs/pages/server/labymod/supplements/server-switch.md new file mode 100644 index 0000000..cf47357 --- /dev/null +++ b/docs/pages/server/labymod/supplements/server-switch.md @@ -0,0 +1,89 @@ +The `ServerSwitchPromptPacket` is a client-bound packet that allows you to open a prompt for the player that +recommends switching to another server. The player can then confirm or cancel the server switch. + +The client will then respond with a `ServerSwitchPromptResponsePacket` that contains the player's decision. + +![Example Server Switch Prompt](/assets/files/serverapi/server-switch-prompt.png) + +## Creating an Input Prompt + +The packet uses the `ServerSwitchPrompt` model, which can be created with `ServerSwitchPrompt.create`. +The ServerSwitchPrompt model uses the Server API's own Component model. + +```java +ServerSwitchPrompt serverSwitchPrompt = ServerSwitchPrompt.create( + ServerAPIComponent.text("Example Server Switch Prompt") + .color(ServerAPITextColor.GOLD) + .decorate(ServerAPITextDecoration.BOLD), + "hypixel.net" +); +``` + +## Sending the Packet + +The packet can either be sent via the `LabyModPlayer` object of the player, or directly via the `LabyModProtocol`. + +If you're not sending the packet with an integrated handler, you need to register a handler for the `ServerSwitchPromptResponsePacket` yourself. The process is explained [here](/pages/server/protocols/#registering-handlers). + +### Via LabyModPlayer (Recommended) + +=== ":octicons-file-code-16: #openServerSwitchPrompt(ServerSwitchPrompt, Consumer)" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Open the server switch prompt and handle the response + labyModPlayer.openServerSwitchPrompt(serverSwitchPrompt, response -> { + boolean accepted = response.wasAccepted(); // Whether the player accepted the server switch + // Directly handle the response + }); + ``` + +=== ":octicons-file-code-16: #openServerSwitchPrompt(ServerSwitchPrompt)" + + ```java + // Get the LabyModPlayer + LabyModPlayer labyModPlayer = LabyModProtocolService.get().getPlayer(uniqueId); + + // Open the server switch prompt + labyModPlayer.openServerSwitchPrompt(serverSwitchPrompt); + + // To handle the response, you need to register a PacketHandler for the + // ServerSwitchPromptResponsePacket yourself! + ``` + +### Via the LabyModProtocol + +=== ":octicons-file-code-16: #sendPacket(UUID, Packet)" + + ```java + // Get the LabyModProtocol + LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + + // Send the packet + labyModProtocol.sendPacket(uniqueId, new ServerSwitchPromptPacket(inputPrompt)); + + // To handle the response, you need to register a PacketHandler for the + // ServerSwitchPromptResponsePacket yourself! + ``` + +=== ":octicons-file-code-16: #sendPacket(UUID, IdentifiablePacket, Class, Predicate)" + + ```java + // Get the LabyModProtocol + LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + + // Send the packet and handle the response + labyModProtocol.sendPacket( + uniqueId, + new ServerSwitchPromptPacket(inputPrompt), + ServerSwitchPromptResponsePacket.class, + response -> { + boolean accepted = response.wasAccepted(); // Whether the player accepted the server switch + // Handle the response packet + + return false; // Return false, as only one response is expected + } + ); + ``` \ No newline at end of file diff --git a/docs/pages/server/packets.md b/docs/pages/server/packets.md new file mode 100644 index 0000000..ec29f74 --- /dev/null +++ b/docs/pages/server/packets.md @@ -0,0 +1,188 @@ +In contrast to the LabyMod 3 Server API, the LabyMod 4 Server API doesn't communicate with JsonElements. Instead, it +writes data directory into a ByteBuffer. This is a more efficient way of communication and allows for more flexibility +in the data that can be sent. + +The downside of this is that it is even more important to read and write packets correctly. Therefore, it is +recommended to share the classes on the server and client-side. The `core` artifact for example, is also shared between +the implementation in LabyMod 4 and the server. + +For an easier process of creating packets, we provide the classes `PayloadReader` and `PayloadWriter`. Both contain +a variety of methods to read and write data from and to the ByteBuffer for any types thinkable. From collections and +arrays to nullable objects. + +If you are still unsure if you are doing everything correctly, please don't hesitate to check out the Packets of the +LabyMod Protocol +on [GitHub](https://github.com/LabyMod/labymod4-server-api/tree/master/core/src/main/java/net/labymod/serverapi/core/packet) +or ask on [our Discord Server for Developers](https://labymod.net/dc/dev). + +## Creating a Packet + +For our example packet, we'll be reading and writing a nullable component, an integer and a collection of objects with a +string and a bunch of booleans. + +First, we'll create that implements the `Packet` interface. And create all the fields we want to read and write. Also, +we create a record for the object that our List will contain.
+__Don't mind the field names, they are just placeholders for this example.__ + +```java +import net.labymod.serverapi.api.model.component.ServerAPIComponent; +import net.labymod.serverapi.api.packet.Packet; +import net.labymod.serverapi.api.payload.io.PayloadReader; +import net.labymod.serverapi.api.payload.io.PayloadWriter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +public class ExamplePacket implements Packet { + + private ServerAPIComponent component; + private int color; + private List objects; + + public ExamplePacket( + @Nullable ServerAPIComponent component, + @NotNull List objects, + int color + ) { + // Throw an exception if the list is null + Objects.requireNonNull(objects, "Objects list cannot be null"); + + // Assign the values to the fields + this.component = component; + this.objects = objects; + this.color = color; + } + + public @Nullable ServerAPIComponent getComponent() { + return this.component; + } + + public int getColor() { + return this.color; + } + + /** + * This can be annotated with {@link NotNull}, as the list is never null. + * We know that because our constructor is throwing an exception if no list + * is provided. And if for some reason the list is null upon reading, it + * will never be handed over to the PacketHandler. + */ + public @NotNull List getObjects() { + return this.objects; + } + + /** + * It's always a good idea to override the {@link Object#toString()} method to + * provide a human-readable representation of the object. + */ + @Override + public String toString() { + return "ExamplePacket{" + + "component=" + component + + ", color=" + color + + '}'; + } + + /** + * The record is a simple data class that is used to store the data of + * the objects list. + */ + public record ExamplePacketObject( + String name, + boolean editable, + boolean createdByUser, + boolean global + ) { + + /** + * It's always a good idea to override the {@link Object#toString()} method + * to provide a human-readable representation of the object. + */ + @Override + public String toString() { + return "ExamplePacketObject{" + + "name='" + name + '\'' + + ", editable=" + editable + + ", createdByUser=" + createdByUser + + ", global=" + global + + '}'; + } + } +} +``` + +## Write the Packet + +To write the packet, we need to override the `write` method of the `Packet` interface. Be sure not to call +`super.write`, as this will throw an exception upon writing the packet. + +???+ danger "Important" + Always keep in mind that the order of writing and reading the values of the Packet must be the same, also the types must match. You can't write a variable integer and read a normal integer. If you are unsure what to do (or whether what you've done is correct), don't hesitate to ask on [our Discord Server for Developers](https://labymod.net/dc/dev). + +```java +@Override +public void write(@NotNull PayloadWriter writer) { + // Write the nullable component + writer.writeOptional( + this.component, // The component + writer::writeComponent // the consumer to write the component + ); + + // Write the color. We're using writeVarInt here, as variable integers are + // more efficient on the network stack for smaller values. Alternatively + // you can use PayloadWriter#writeInt + writer.writeVarInt(this.color); + + // Write the list of objects + writer.writeCollection( + this.objects, // The list to write + object -> { // the consumer is called for every object in the list + // write the name + writer.writeString(object.name()); + + // write the boolean values + writer.writeBoolean(object.editable()); + writer.writeBoolean(object.createdByUser()); + writer.writeBoolean(object.global()); + } + ); +} +``` + +## Read the Packet + +To read the packet, we need to override the `read` method of the `Packet` interface. Be sure not to call +`super.read`, as this will throw an exception upon reading the packet. + +???+ danger "Important" + Always keep in mind that the order of writing and reading the values of the Packet must be the same, also the types must match. You can't write a variable integer and read a normal integer. If you are unsure what to do (or if what you've done is correct), don't hesitate to ask on [our Discord Server for Developers](https://labymod.net/dc/dev). + +```java +@Override +public void read(@NotNull PayloadReader reader) { + // Read the optional component + this.component = reader.readOptional(reader::readComponent); + + // Read the color as variable integer. + this.color = reader.readVarInt(); + + // Read the list of objects + this.objects = reader.readList(() -> { // the supplier is called for every object in the list + return new ExamplePacketObject( + reader.readString(), // read the name + reader.readBoolean(), // read the editable boolean + reader.readBoolean(), // read the createdByUser boolean + reader.readBoolean() // read the global boolean + ); + }); +} +``` + +## Final Words + +That's it. You've successfully created a packet that can be sent the to or from the server. +Now all you have to do is to [register the Packet](/pages/server/protocols/#register-a-packet) in your Protocol.
+ + + diff --git a/docs/pages/server/protocols.md b/docs/pages/server/protocols.md new file mode 100644 index 0000000..1e5b303 --- /dev/null +++ b/docs/pages/server/protocols.md @@ -0,0 +1,97 @@ +Protocols are collections of packets that are used to communicate between the client and the server.
+Addons can create custom protocols to send and receive custom packets.
+The LabyMod 4 Server API provides the LabyMod Protocol that is used to communicate with the LabyMod client. + +## The LabyMod Protocol + +The LabyMod Protocol is the default protocol, it contains all official features that servers can use to customize the +experience of LabyMod players. + +A collection of all available features can be found [here](/pages/server/labymod/overview). + +### Registering Handlers + +To register a packet handler in the LabyMod Protocol, you first need to create a new class implementing the +`PacketHandler` interface. We'll use the [VersionLoginPacket](/pages/server/labymod/moderation/labymod-version/) in the +following example. + +```java +import net.labymod.serverapi.api.packet.PacketHandler; +import net.labymod.serverapi.core.packet.serverbound.login.VersionLoginPacket; +import org.jetbrains.annotations.NotNull; + +import java.util.UUID; + +public class VersionLoginPacketHandler implements PacketHandler { + + /** + * Handles the VersionLoginPacket + * + * @param sender the unique id of the sender of the packet + * @param packet the packet that was sent + */ + @Override + public void handle(@NotNull UUID sender, @NotNull VersionLoginPacket packet) { + // Perform logic to handle the packet + } +} +``` + +After creating the handler, you can register it in the LabyMod Protocol. + +```java +// Get the LabyModProtocol +LabyModProtocol labyModProtocol = LabyModProtocolService.get().labyModProtocol(); + +// Register the handler +labyModProtocol.registerHandler( + VersionLoginPacket.class, // The packet class + new VersionLoginPacketHandler() // Object of the handler (can also be a lambda) +); +``` + +## Create a Custom Protocol + +To create a custom protocol, you can create a new instance of `AddonProtocol` by calling the constructor +with the protocol service and namespace as parameters. Then register the protocol in the ProtocolRegistry. + +```java +// Get the Protocol Service +LabyModProtocolService protocolService = LabyModProtocolService.get(); + +// Create a new AddonProtocol +AddonProtocol protocol = new AddonProtocol(protocolService, "example"); + +// Register the protocol +protocolService.registry().registerProtocol(protocol); +``` + +### Register a Packet + +To register a packet, you first need to [create a Packet](/pages/server/packets/). After doing that, you can just +register the packet in the protocol. + +=== ":octicons-code-16: With Handler" + + ```java + // Register the Packet with handler + protocol.registerPacket( + 0, // the id of the packet. Must be unique in the protocol on both sides + ExamplePacket.class, // the class of the packet + Direction.CLIENTBOUND, // the direction of the packet. Can also be SERVERBOUND or BOTH + new ExamplePacketHandler() // the handler of the packet + ); + ``` + +=== ":octicons-code-16: Without Handler" + + ```java + // Register the Packet without handler. Handler can be registered later. + // See above for registering a handler separately + protocol.registerPacket( + 0, // the id of the packet. Must be unique in the protocol on both sides + ExamplePacket.class, // the class of the packet + Direction.CLIENTBOUND // the direction of the packet. Can also be SERVERBOUND or BOTH + ); + ``` + diff --git a/mkdocs.yml b/mkdocs.yml index 75de616..a56969b 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -1,28 +1,70 @@ -site_name: LabyMod4 API +site_name: LabyMod 4 Developer Portal +repo_url: https://github.com/LabyMod/labymod4-api-wiki/ +repo_name: LabyMod/labymod4-api-wiki +edit_uri: https://github.com/LabyMod/labymod4-api-wiki/tree/master/docs/ +copyright: Copyright © 2024 LabyMedia GmbH - Imprint nav: + - Home: + - Introduction: index.md + - Contributors: contributors.md + - Documentation: + - Server API: /pages/server + - Addon API: /pages/addon + - Server API: + - Server API Setup: pages/server/index.md + - Working with Protocols: pages/server/protocols.md + - Creating Packets: pages/server/packets.md + - Creating Integrations: pages/server/integrations.md + - LabyMod Protocol: + - Overview: pages/server/labymod/overview.md + - Server Displays: + - Economy Display: pages/server/labymod/displays/economy.md + - Subtitles: pages/server/labymod/displays/subtitles.md + - Tablist Banner: pages/server/labymod/displays/tablist-banner.md + - Tablist Flags: pages/server/labymod/displays/tablist-flags.md + - Features: + - Discord RPC: pages/server/labymod/features/discord.md + - Emotes: pages/server/labymod/features/emotes.md + - Gamemode: pages/server/labymod/features/gamemode.md + - Interaction Menu: pages/server/labymod/features/interaction-menu.md + - Markers: pages/server/labymod/features/markers.md + - Moderation: + - Addon Recommendations: pages/server/labymod/moderation/addon-recommendation.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: + - VoiceChat: + - Overview: pages/server/addons/voicechat/index.md + - Mute Players: pages/server/addons/voicechat/mute.md + - Unmute a Player: pages/server/addons/voicechat/unmute.md + - Open Channels: pages/server/addons/voicechat/open-channels.md + - Contributors: /contributors - Addon API: - - Introduction: pages/addon/index.md - - Setup: - - First Steps: pages/addon/setup/first-steps.md - - Your first LabyMod 4 Addon: pages/addon/setup/setup.md - - Features: - - Creating a Configuration: pages/addon/features/config.md - - Internationalize your Addon: pages/addon/features/internationalization.md - - Use and Create Events: pages/addon/features/events.md - - Create Commands: pages/addon/features/commands.md - - Write Version Dependent Code: pages/addon/features/version-dependent.md - - Activity System: - - What are Activities?: pages/addon/activities/activity.md - - Use and Create Widgets: pages/addon/activities/widgets.md - - Understand LSS: pages/addon/activities/lss.md - - Theming: pages/addon/activities/themes.md - - Publishing: - - Guidelines: pages/addon/publishing/guidelines.md - - Publish Your Addon: pages/addon/publishing/publish.md - - Troubleshoot: pages/addon/troubleshoot.md - - Additional Information: pages/addon/additional-infos.md - - Contributors: pages/addon/contributors.md + - Addon API Introduction: pages/addon/index.md + - Setup: + - First Steps: pages/addon/setup/first-steps.md + - Your First LabyMod 4 Addon: pages/addon/setup/setup.md + - Features: + - Creating a Configuration: pages/addon/features/config.md + - Internationalize your Addon: pages/addon/features/internationalization.md + - Use and Create Events: pages/addon/features/events.md + - Create Commands: pages/addon/features/commands.md + - Write Version Dependent Code: pages/addon/features/version-dependent.md + - Activity System: + - What are Activities?: pages/addon/activities/activity.md + - Use and Create Widgets: pages/addon/activities/widgets.md + - Understand LSS: pages/addon/activities/lss.md + - Theming: pages/addon/activities/themes.md + - Publishing: + - Guidelines: pages/addon/publishing/guidelines.md + - Publish Your Addon: pages/addon/publishing/publish.md + - Troubleshoot: pages/addon/troubleshoot.md + - Additional Information: pages/addon/additional-infos.md + - Contributors: /contributors plugins: - search @@ -39,6 +81,7 @@ markdown_extensions: theme: name: material + custom_dir: overrides favicon: 'assets/theme/images/favicon.ico' logo: 'assets/theme/images/wolf.png' palette: @@ -46,8 +89,16 @@ theme: feature: tabs: true features: + - navigation.sections - navigation.tabs - navigation.expand + - content.tabs.link + - content.action.edit + - navigation.footer + - search.highlight -extra_javascript: ['assets/theme/js/script.js'] -extra_css: ['assets/theme/css/main.css'] \ No newline at end of file +extra_javascript: [ 'assets/theme/js/script.js' ] +extra_css: [ 'assets/theme/css/main.css' ] + +extra: + generator: false \ No newline at end of file diff --git a/overrides/partials/copyright.html b/overrides/partials/copyright.html new file mode 100644 index 0000000..8134a2d --- /dev/null +++ b/overrides/partials/copyright.html @@ -0,0 +1,6 @@ + \ No newline at end of file