From 598e172eb1a1a204f1c5570c5963a7199006c6dc Mon Sep 17 00:00:00 2001 From: ItsNature Date: Thu, 27 Aug 2026 01:06:42 +0200 Subject: [PATCH 1/6] Deploy as `1.3.0-SNAPSHOT` --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 5909961d..425cdaa5 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=com.lunarclient -version=1.2.9 +version=1.3.0-SNAPSHOT description=The API for interacting with Lunar Client players. org.gradle.parallel=true From 5898f79ac6d07fe41da59e317ebbb11b6b3c8a9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Bu=C4=8Dari=C4=87?= Date: Wed, 7 Oct 2026 16:58:05 +0200 Subject: [PATCH 2/6] Add Totem Counter Module (#311) --- .github/workflows/deploy.yml | 2 +- .../module/totemcounter/TotemCounter.java | 57 +++ .../totemcounter/TotemCounterModule.java | 123 +++++ .../totemcounter/TotemCounterModuleImpl.java | 96 ++++ .../lightweight/json/packet-util.mdx | 3 +- docs/developers/lightweight/protobuf.mdx | 6 +- .../lightweight/protobuf/packet-util.mdx | 3 +- docs/developers/modules.mdx | 1 + docs/developers/modules/_meta.json | 1 + docs/developers/modules/totemcounter.mdx | 447 ++++++++++++++++++ .../example/api/ApolloApiExamplePlatform.java | 2 + .../api/module/TotemCounterApiExample.java | 140 ++++++ .../bukkit/api/src/main/resources/plugin.yml | 2 + .../apollo/example/ApolloExamplePlugin.java | 4 + .../example/command/TotemCounterCommand.java | 94 ++++ .../module/impl/TotemCounterExample.java | 41 ++ .../apollo/example/util/ServerUtil.java | 9 + .../json/ApolloJsonExamplePlatform.java | 2 + .../json/module/TotemCounterJsonExample.java | 167 +++++++ .../example/json/util/JsonPacketUtil.java | 3 +- .../bukkit/json/src/main/resources/plugin.yml | 2 + .../proto/ApolloProtoExamplePlatform.java | 2 + .../module/TotemCounterProtoExample.java | 158 +++++++ .../proto/util/ProtobufPacketUtil.java | 3 +- .../proto/src/main/resources/plugin.yml | 2 + gradle/libs.versions.toml | 2 +- .../apollo/ApolloBukkitPlatform.java | 3 + .../apollo/ApolloBungeePlatform.java | 3 + .../apollo/ApolloFoliaPlatform.java | 3 + .../apollo/ApolloMinestomPlatform.java | 3 + .../apollo/ApolloVelocityPlatform.java | 3 + 31 files changed, 1378 insertions(+), 9 deletions(-) create mode 100644 api/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounter.java create mode 100644 api/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounterModule.java create mode 100644 common/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounterModuleImpl.java create mode 100644 docs/developers/modules/totemcounter.mdx create mode 100644 example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/TotemCounterApiExample.java create mode 100644 example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/TotemCounterCommand.java create mode 100644 example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/TotemCounterExample.java create mode 100644 example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/TotemCounterJsonExample.java create mode 100644 example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/TotemCounterProtoExample.java diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index f65bf2a7..4a465fe7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -41,7 +41,7 @@ jobs: fi - name: Gradle Publish - if: "${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/version/') }}" + if: "${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/version/') || github.ref == 'refs/heads/feature/totem-counter-module' }}" run: ./gradlew publish - name: Gradle Release diff --git a/api/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounter.java b/api/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounter.java new file mode 100644 index 00000000..3848c14f --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounter.java @@ -0,0 +1,57 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.module.totemcounter; + +import java.util.UUID; +import lombok.Builder; +import lombok.Getter; +import org.jetbrains.annotations.Range; + +/** + * Represents a totem counter which can be shown on the client. + * + * @since 1.3.0 + */ +@Getter +@Builder +public final class TotemCounter { + + /** + * Returns the totem counter player's {@link UUID}. + * + * @return the player uuid + * @since 1.3.0 + */ + UUID playerUuid; + + /** + * Returns the totem counter {@link Integer} amount of totems the player + * has popped. + * + * @return the totem counter pops + * @since 1.3.0 + */ + @Range(from = 0, to = Integer.MAX_VALUE) int pops; + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounterModule.java b/api/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounterModule.java new file mode 100644 index 00000000..6599551b --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounterModule.java @@ -0,0 +1,123 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.module.totemcounter; + +import com.lunarclient.apollo.module.ApolloModule; +import com.lunarclient.apollo.module.ModuleDefinition; +import com.lunarclient.apollo.option.Option; +import com.lunarclient.apollo.option.SimpleOption; +import com.lunarclient.apollo.recipients.Recipients; +import io.leangen.geantyref.TypeToken; +import java.util.Collection; +import java.util.UUID; +import org.jetbrains.annotations.ApiStatus; + +/** + * Represents the totem counter module. + * + *

Overrides the totem pops shown by the client's Totem Counter mod. + * The client keeps counting totem pops on its own on top of the overridden + * values, unless {@link #DISABLE_LOCAL_TRACKING} is enabled.

+ * + * @since 1.3.0 + */ +@ApiStatus.NonExtendable +@ModuleDefinition(id = "totem_counter", name = "Totem Counter") +public abstract class TotemCounterModule extends ApolloModule { + + /** + * Whether the client stops tracking and resetting totem pops on its own. + * + * @since 1.3.0 + */ + public static final SimpleOption DISABLE_LOCAL_TRACKING = Option.builder() + .comment("Set to 'true' to stop the client from tracking and resetting totem pops on its own, otherwise 'false'.") + .node("disable-local-tracking").type(TypeToken.get(Boolean.class)) + .defaultValue(false).notifyClient().build(); + + protected TotemCounterModule() { + this.registerOptions( + TotemCounterModule.DISABLE_LOCAL_TRACKING + ); + } + + @Override + public boolean isClientNotify() { + return true; + } + + /** + * Overrides the {@link TotemCounter}s for the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @param totemCounters the totem counters + * @since 1.3.0 + */ + public abstract void overrideTotemCounters(Recipients recipients, Collection totemCounters); + + /** + * Overrides the {@link TotemCounter} for the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @param totemCounter the totem counter + * @since 1.3.0 + */ + public abstract void overrideTotemCounter(Recipients recipients, TotemCounter totemCounter); + + /** + * Resets the {@link TotemCounter} for the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @param playerUuid the player whose totem counter we are manipulating + * @since 1.3.0 + */ + public abstract void resetTotemCounter(Recipients recipients, UUID playerUuid); + + /** + * Resets the {@link TotemCounter} for the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @param totemCounter the totem counter + * @since 1.3.0 + */ + public abstract void resetTotemCounter(Recipients recipients, TotemCounter totemCounter); + + /** + * Resets the {@link TotemCounter}s for the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @param playerUuids the players whose totem counters we are manipulating + * @since 1.3.0 + */ + public abstract void resetTotemCounter(Recipients recipients, Collection playerUuids); + + /** + * Resets all {@link TotemCounter}s for the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @since 1.3.0 + */ + public abstract void resetTotemCounters(Recipients recipients); + +} diff --git a/common/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounterModuleImpl.java b/common/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounterModuleImpl.java new file mode 100644 index 00000000..94d1a20d --- /dev/null +++ b/common/src/main/java/com/lunarclient/apollo/module/totemcounter/TotemCounterModuleImpl.java @@ -0,0 +1,96 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.module.totemcounter; + +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.network.NetworkTypes; +import com.lunarclient.apollo.recipients.Recipients; +import com.lunarclient.apollo.totemcounter.v1.OverrideTotemCountersMessage; +import com.lunarclient.apollo.totemcounter.v1.ResetTotemCounterMessage; +import com.lunarclient.apollo.totemcounter.v1.ResetTotemCountersMessage; +import java.util.Collection; +import java.util.Collections; +import java.util.UUID; +import lombok.NonNull; + +import static com.lunarclient.apollo.util.Ranges.checkPositive; + +/** + * Provides the totem counter module. + * + * @since 1.3.0 + */ +public final class TotemCounterModuleImpl extends TotemCounterModule { + + @Override + public void overrideTotemCounters(@NonNull Recipients recipients, @NonNull Collection totemCounters) { + OverrideTotemCountersMessage.Builder builder = OverrideTotemCountersMessage.newBuilder(); + + for (TotemCounter totemCounter : totemCounters) { + builder.addTotemCounters(this.toProtobuf(totemCounter)); + } + + ApolloManager.getNetworkManager().sendPacket(recipients, builder.build()); + } + + @Override + public void overrideTotemCounter(@NonNull Recipients recipients, @NonNull TotemCounter totemCounter) { + this.overrideTotemCounters(recipients, Collections.singleton(totemCounter)); + } + + @Override + public void resetTotemCounter(@NonNull Recipients recipients, @NonNull UUID playerUuid) { + this.resetTotemCounter(recipients, Collections.singleton(playerUuid)); + } + + @Override + public void resetTotemCounter(@NonNull Recipients recipients, @NonNull TotemCounter totemCounter) { + this.resetTotemCounter(recipients, Collections.singleton(totemCounter.getPlayerUuid())); + } + + @Override + public void resetTotemCounter(@NonNull Recipients recipients, @NonNull Collection playerUuids) { + ResetTotemCounterMessage.Builder builder = ResetTotemCounterMessage.newBuilder(); + + for (UUID playerUuid : playerUuids) { + builder.addPlayerUuids(NetworkTypes.toProtobuf(playerUuid)); + } + + ApolloManager.getNetworkManager().sendPacket(recipients, builder.build()); + } + + @Override + public void resetTotemCounters(@NonNull Recipients recipients) { + ResetTotemCountersMessage message = ResetTotemCountersMessage.getDefaultInstance(); + ApolloManager.getNetworkManager().sendPacket(recipients, message); + } + + private com.lunarclient.apollo.totemcounter.v1.TotemCounter toProtobuf(TotemCounter totemCounter) { + return com.lunarclient.apollo.totemcounter.v1.TotemCounter.newBuilder() + .setPlayerUuid(NetworkTypes.toProtobuf(totemCounter.getPlayerUuid())) + .setPops(checkPositive(totemCounter.getPops(), "TotemCounter#pops")) + .build(); + } + +} diff --git a/docs/developers/lightweight/json/packet-util.mdx b/docs/developers/lightweight/json/packet-util.mdx index ee5ec7d0..c1517c7c 100644 --- a/docs/developers/lightweight/json/packet-util.mdx +++ b/docs/developers/lightweight/json/packet-util.mdx @@ -15,7 +15,7 @@ To utilize Apollo Modules, first define a list of the modules you want to use: ```java private static final List APOLLO_MODULES = Arrays.asList("auto_text_hotkey", "beam", "border", "chat", "colored_fire", "combat", "cooldown", "entity", "glint", "glow", "hologram", "inventory", "limb", "mod_setting", "nametag", "nick_hider", "notification", "pay_now", "packet_enrichment", - "rich_presence", "saturation", "server_link", "server_rule", "staff_mod", "stopwatch", "team", "tebex", "title", "tnt_countdown", "transfer", "vignette", "waypoint" + "rich_presence", "saturation", "server_link", "server_rule", "staff_mod", "stopwatch", "team", "tebex", "title", "tnt_countdown", "totem_counter", "transfer", "vignette", "waypoint" ); ``` @@ -59,6 +59,7 @@ static { CONFIG_MODULE_PROPERTIES.put("server_rule", "crystal-optimizer", false); CONFIG_MODULE_PROPERTIES.put("tnt_countdown", "tnt-ticks", 80); CONFIG_MODULE_PROPERTIES.put("title", "clear-title-on-server-switch", false); + CONFIG_MODULE_PROPERTIES.put("totem_counter", "disable-local-tracking", false); CONFIG_MODULE_PROPERTIES.put("waypoint", "server-handles-waypoints", false); } ``` diff --git a/docs/developers/lightweight/protobuf.mdx b/docs/developers/lightweight/protobuf.mdx index 0bb373d6..5845b980 100644 --- a/docs/developers/lightweight/protobuf.mdx +++ b/docs/developers/lightweight/protobuf.mdx @@ -26,7 +26,7 @@ Available fields for each message, including their types, are available on the B com.lunarclient apollo-protos - 0.2.4 + 0.2.5 ``` @@ -41,7 +41,7 @@ Available fields for each message, including their types, are available on the B } dependencies { - api 'com.lunarclient:apollo-protos:0.2.4' + api 'com.lunarclient:apollo-protos:0.2.5' } ``` @@ -55,7 +55,7 @@ Available fields for each message, including their types, are available on the B } dependencies { - api("com.lunarclient:apollo-protos:0.2.4") + api("com.lunarclient:apollo-protos:0.2.5") } ``` diff --git a/docs/developers/lightweight/protobuf/packet-util.mdx b/docs/developers/lightweight/protobuf/packet-util.mdx index 67e7b9d5..cd7bee5b 100644 --- a/docs/developers/lightweight/protobuf/packet-util.mdx +++ b/docs/developers/lightweight/protobuf/packet-util.mdx @@ -15,7 +15,7 @@ To utilize Apollo Modules, first define a list of the modules you want to use: ```java private static final List APOLLO_MODULES = Arrays.asList("auto_text_hotkey", "beam", "border", "chat", "colored_fire", "combat", "cooldown", "entity", "glint", "glow", "hologram", "inventory", "limb", "mod_setting", "nametag", "nick_hider", "notification", "pay_now", "packet_enrichment", - "rich_presence", "saturation", "server_link", "server_rule", "staff_mod", "stopwatch", "team", "tebex", "title", "tnt_countdown", "transfer", "vignette", "waypoint" + "rich_presence", "saturation", "server_link", "server_rule", "staff_mod", "stopwatch", "team", "tebex", "title", "tnt_countdown", "totem_counter", "transfer", "vignette", "waypoint" ); ``` @@ -65,6 +65,7 @@ static { CONFIG_MODULE_PROPERTIES.put("server_rule", "crystal-optimizer", Value.newBuilder().setBoolValue(false).build()); CONFIG_MODULE_PROPERTIES.put("tnt_countdown", "tnt-ticks", Value.newBuilder().setNumberValue(80).build()); CONFIG_MODULE_PROPERTIES.put("title", "clear-title-on-server-switch", Value.newBuilder().setBoolValue(false).build()); + CONFIG_MODULE_PROPERTIES.put("totem_counter", "disable-local-tracking", Value.newBuilder().setBoolValue(false).build()); CONFIG_MODULE_PROPERTIES.put("waypoint", "server-handles-waypoints", Value.newBuilder().setBoolValue(false).build()); } ``` diff --git a/docs/developers/modules.mdx b/docs/developers/modules.mdx index 1d8f8fc7..cdf6d7f8 100644 --- a/docs/developers/modules.mdx +++ b/docs/developers/modules.mdx @@ -37,6 +37,7 @@ These modules are available to all servers using Apollo and do not require any p 🔗 [Tebex](/apollo/developers/modules/tebex)
🔗 [Title](/apollo/developers/modules/title)
🔗 [TNT Countdown](/apollo/developers/modules/tntcountdown)
+🔗 [Totem Counter](/apollo/developers/modules/totemcounter)
🔗 [Transfer](/apollo/developers/modules/transfer)
🔗 [Vignette](/apollo/developers/modules/vignette)
🔗 [Waypoint](/apollo/developers/modules/waypoint)
diff --git a/docs/developers/modules/_meta.json b/docs/developers/modules/_meta.json index 11e872d0..4b5b8831 100644 --- a/docs/developers/modules/_meta.json +++ b/docs/developers/modules/_meta.json @@ -30,6 +30,7 @@ "tebex": "Tebex", "title": "Title", "tntcountdown": "TNT Countdown", + "totemcounter": "Totem Counter", "transfer": "Transfer", "vignette": "Vignette", "waypoint": "Waypoint" diff --git a/docs/developers/modules/totemcounter.mdx b/docs/developers/modules/totemcounter.mdx new file mode 100644 index 00000000..ce112998 --- /dev/null +++ b/docs/developers/modules/totemcounter.mdx @@ -0,0 +1,447 @@ +import { Callout, Tab, Tabs } from 'nextra-theme-docs' + +# Totem Counter Module + +## Overview + +The totem counter module allows servers to control the totem pops displayed by the Totem Counter mod. + +- Adds the ability to override the totem pops of any player, shown on their nametag, tab list entry and the Totem Counter HUD. + - Display totem pops the client can't track on its own, such as pops outside of tracking range or before the player joined. + - Ability to stop the client from tracking and resetting totem pops on its own. + +An overridden totem counter replaces the client's own count for that player, and the client keeps counting on top of it unless `DISABLE_LOCAL_TRACKING` is enabled. + + + This module is only supported for 1.12 and above versions of Lunar Client. + + + + The Totem Counter mod is disabled by default, totem counters sent while it is disabled are ignored. See the [Totem Counter mod](/apollo/developers/mods/totemcounter) page to enable it for your players. + + +## Integration + + + Enable `DISABLE_LOCAL_TRACKING` when sending every totem pop, otherwise the client also counts each pop and shows one more. + + +### Sample Code +Explore each integration by cycling through each tab, to find the best fit for your requirements and needs. + + + + + + +**Apollo API examples.** See [General](/apollo/developers/general) for common patterns and helpers. + + +### Overriding a Totem Counter + +```java +public void overrideTotemCounterExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + this.totemCounterModule.overrideTotemCounter(apolloPlayer, TotemCounter.builder() + .playerUuid(viewer.getUniqueId()) + .pops(3) + .build() + ); + }); +} +``` + +### Overriding multiple Totem Counters + +```java +public void overrideTotemCountersExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + List totemCounters = Bukkit.getOnlinePlayers() + .stream().map(player -> TotemCounter.builder() + .playerUuid(player.getUniqueId()) + .pops(2) + .build()) + .collect(Collectors.toList()); + + this.totemCounterModule.overrideTotemCounters(apolloPlayer, totemCounters); + }); +} +``` + +### Resetting a Totem Counter + +The client forgets the player's totem pops, including the ones it tracked on its own. + +```java +public void resetTotemCounterExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.totemCounterModule.resetTotemCounter(apolloPlayer, viewer.getUniqueId())); +} +``` + +### Resetting all Totem Counters + +The client forgets every player's totem pops, including the ones it tracked on its own. + +```java +public void resetTotemCountersExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(this.totemCounterModule::resetTotemCounters); +} +``` + +### Tracking Totem Pops + +```java +private final Map totemPops = new ConcurrentHashMap<>(); + +@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +private void onEntityResurrect(EntityResurrectEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + + Player player = (Player) event.getEntity(); + int pops = this.totemPops.merge(player.getUniqueId(), 1, Integer::sum); + + // Pops are absolute, send the new total instead of an increment + this.totemCounterModule.overrideTotemCounter(Recipients.ofEveryone(), TotemCounter.builder() + .playerUuid(player.getUniqueId()) + .pops(pops) + .build() + ); +} + +@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +private void onPlayerDeath(PlayerDeathEvent event) { + this.resetTotemPops(event.getEntity()); +} + +@EventHandler +private void onPlayerQuit(PlayerQuitEvent event) { + this.resetTotemPops(event.getPlayer()); +} + +private void resetTotemPops(Player player) { + if (this.totemPops.remove(player.getUniqueId()) != null) { + this.totemCounterModule.resetTotemCounter(Recipients.ofEveryone(), player.getUniqueId()); + } +} +``` + +### Toggle Local Tracking + +```java +public void setDisableLocalTracking(boolean value) { + this.totemCounterModule.getOptions().set(TotemCounterModule.DISABLE_LOCAL_TRACKING, value); +} +``` + +### `overrideTotemCounter` & `overrideTotemCounters` Parameters + +1. `Recipients recipients` + - A list of all the player(s) you want to be able to see the updated totem counters. +2. `TotemCounter totemCounter` or `Collection totemCounters` + - The totem counter(s) you want to display. See the [`TotemCounter` Options](#totemcounter-options) section for more. + +### `resetTotemCounter` Parameters + +1. `Recipients recipients` + - A list of all the player(s) you want to be able to see the updated totem counter. +2. `UUID playerUuid`, `TotemCounter totemCounter` or `Collection playerUuids` + - The player(s) you want to reset the totem counter of. + +### `TotemCounter` Options + +`.playerUuid(UUID)` is the player, by UUID, that you wish to apply the totem counter to. Sending a totem counter for an already known player replaces that player's pops. + +```java +.playerUuid(viewer.getUniqueId()) +``` + +`.pops(Integer)` is the amount of totems the player has popped. Values are absolute, not increments, so sending the same value twice is harmless. The client keeps counting from this value, unless `DISABLE_LOCAL_TRACKING` is enabled. + +```java +.pops(3) +``` + + + + + + +**Lightweight Protobuf examples.** See [Lightweight Protobuf](/apollo/developers/lightweight/protobuf) for setup. + + +**Overriding a Totem Counter** + +```java +public void overrideTotemCounterExample(Player viewer) { + TotemCounter totemCounter = TotemCounter.newBuilder() + .setPlayerUuid(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .setPops(3) + .build(); + + OverrideTotemCountersMessage message = OverrideTotemCountersMessage.newBuilder() + .addTotemCounters(totemCounter) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + +**Overriding multiple Totem Counters** + +```java +public void overrideTotemCountersExample(Player viewer) { + List totemCounters = Bukkit.getOnlinePlayers() + .stream().map(player -> TotemCounter.newBuilder() + .setPlayerUuid(ProtobufUtil.createUuidProto(player.getUniqueId())) + .setPops(2) + .build()) + .collect(Collectors.toList()); + + OverrideTotemCountersMessage message = OverrideTotemCountersMessage.newBuilder() + .addAllTotemCounters(totemCounters) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + +**Resetting a Totem Counter** + +```java +public void resetTotemCounterExample(Player viewer) { + ResetTotemCounterMessage message = ResetTotemCounterMessage.newBuilder() + .addPlayerUuids(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + +**Resetting all Totem Counters** + +```java +public void resetTotemCountersExample(Player viewer) { + ResetTotemCountersMessage message = ResetTotemCountersMessage.getDefaultInstance(); + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + +**Tracking Totem Pops** + +```java +private final Map totemPops = new ConcurrentHashMap<>(); + +@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +private void onEntityResurrect(EntityResurrectEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + + Player player = (Player) event.getEntity(); + int pops = this.totemPops.merge(player.getUniqueId(), 1, Integer::sum); + + // Pops are absolute, send the new total instead of an increment + TotemCounter totemCounter = TotemCounter.newBuilder() + .setPlayerUuid(ProtobufUtil.createUuidProto(player.getUniqueId())) + .setPops(pops) + .build(); + + OverrideTotemCountersMessage message = OverrideTotemCountersMessage.newBuilder() + .addTotemCounters(totemCounter) + .build(); + + ProtobufPacketUtil.broadcastPacket(message); +} + +@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +private void onPlayerDeath(PlayerDeathEvent event) { + this.resetTotemPops(event.getEntity()); +} + +@EventHandler +private void onPlayerQuit(PlayerQuitEvent event) { + this.resetTotemPops(event.getPlayer()); +} + +private void resetTotemPops(Player player) { + if (this.totemPops.remove(player.getUniqueId()) != null) { + ResetTotemCounterMessage message = ResetTotemCounterMessage.newBuilder() + .addPlayerUuids(ProtobufUtil.createUuidProto(player.getUniqueId())) + .build(); + + ProtobufPacketUtil.broadcastPacket(message); + } +} +``` + +**Toggle Local Tracking** + +```java +public void setDisableLocalTracking(boolean value) { + Map properties = new HashMap<>(); + properties.put("disable-local-tracking", Value.newBuilder().setBoolValue(value).build()); + + ConfigurableSettings settings = ProtobufPacketUtil.createModuleMessage("totem_counter", properties); + ProtobufPacketUtil.broadcastPacket(settings); +} +``` + + + + + + +**Lightweight JSON examples.** See [Lightweight JSON](/apollo/developers/lightweight/json) for setup. + + +**Overriding a Totem Counter** + +```java +public void overrideTotemCounterExample(Player viewer) { + JsonObject totemCounter = new JsonObject(); + totemCounter.add("player_uuid", JsonUtil.createUuidObject(viewer.getUniqueId())); + totemCounter.addProperty("pops", 3); + + JsonArray totemCounters = new JsonArray(); + totemCounters.add(totemCounter); + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.OverrideTotemCountersMessage"); + message.add("totem_counters", totemCounters); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + +**Overriding multiple Totem Counters** + +```java +public void overrideTotemCountersExample(Player viewer) { + JsonArray totemCounters = new JsonArray(); + + for (Player player : Bukkit.getOnlinePlayers()) { + JsonObject totemCounter = new JsonObject(); + totemCounter.add("player_uuid", JsonUtil.createUuidObject(player.getUniqueId())); + totemCounter.addProperty("pops", 2); + + totemCounters.add(totemCounter); + } + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.OverrideTotemCountersMessage"); + message.add("totem_counters", totemCounters); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + +**Resetting a Totem Counter** + +```java +public void resetTotemCounterExample(Player viewer) { + JsonArray playerUuids = new JsonArray(); + playerUuids.add(JsonUtil.createUuidObject(viewer.getUniqueId())); + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.ResetTotemCounterMessage"); + message.add("player_uuids", playerUuids); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + +**Resetting all Totem Counters** + +```java +public void resetTotemCountersExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.ResetTotemCountersMessage"); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + +**Tracking Totem Pops** + +```java +private final Map totemPops = new ConcurrentHashMap<>(); + +@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +private void onEntityResurrect(EntityResurrectEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + + Player player = (Player) event.getEntity(); + int pops = this.totemPops.merge(player.getUniqueId(), 1, Integer::sum); + + // Pops are absolute, send the new total instead of an increment + JsonObject totemCounter = new JsonObject(); + totemCounter.add("player_uuid", JsonUtil.createUuidObject(player.getUniqueId())); + totemCounter.addProperty("pops", pops); + + JsonArray totemCounters = new JsonArray(); + totemCounters.add(totemCounter); + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.OverrideTotemCountersMessage"); + message.add("totem_counters", totemCounters); + + JsonPacketUtil.broadcastPacket(message); +} + +@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +private void onPlayerDeath(PlayerDeathEvent event) { + this.resetTotemPops(event.getEntity()); +} + +@EventHandler +private void onPlayerQuit(PlayerQuitEvent event) { + this.resetTotemPops(event.getPlayer()); +} + +private void resetTotemPops(Player player) { + if (this.totemPops.remove(player.getUniqueId()) != null) { + JsonArray playerUuids = new JsonArray(); + playerUuids.add(JsonUtil.createUuidObject(player.getUniqueId())); + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.ResetTotemCounterMessage"); + message.add("player_uuids", playerUuids); + + JsonPacketUtil.broadcastPacket(message); + } +} +``` + +**Toggle Local Tracking** + +```java +public void setDisableLocalTracking(boolean value) { + Map properties = new HashMap<>(); + properties.put("disable-local-tracking", value); + + JsonObject message = JsonUtil.createEnableModuleObjectWithType("totem_counter", properties); + JsonPacketUtil.broadcastPacket(message); +} +``` + + + + + +## Available options + +- __`DISABLE_LOCAL_TRACKING`__ + - Whether the client stops tracking and resetting totem pops on its own. + - Values + - Type: `Boolean` + - Default: `false` diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/ApolloApiExamplePlatform.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/ApolloApiExamplePlatform.java index d9124449..d43b8bb6 100644 --- a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/ApolloApiExamplePlatform.java +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/ApolloApiExamplePlatform.java @@ -59,6 +59,7 @@ import com.lunarclient.apollo.example.api.module.TebexApiExample; import com.lunarclient.apollo.example.api.module.TitleApiExample; import com.lunarclient.apollo.example.api.module.TntCountdownApiExample; +import com.lunarclient.apollo.example.api.module.TotemCounterApiExample; import com.lunarclient.apollo.example.api.module.TransferApiExample; import com.lunarclient.apollo.example.api.module.VignetteApiExample; import com.lunarclient.apollo.example.api.module.WaypointApiExample; @@ -114,6 +115,7 @@ public void registerModuleExamples() { this.setTebexExample(new TebexApiExample()); this.setTitleExample(new TitleApiExample()); this.setTntCountdownExample(new TntCountdownApiExample()); + this.setTotemCounterExample(new TotemCounterApiExample()); this.setTransferExample(new TransferApiExample()); this.setVignetteExample(new VignetteApiExample()); this.setWaypointExample(new WaypointApiExample()); diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/TotemCounterApiExample.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/TotemCounterApiExample.java new file mode 100644 index 00000000..f916833c --- /dev/null +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/TotemCounterApiExample.java @@ -0,0 +1,140 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.example.api.module; + +import com.lunarclient.apollo.Apollo; +import com.lunarclient.apollo.example.ApolloExamplePlugin; +import com.lunarclient.apollo.example.module.impl.TotemCounterExample; +import com.lunarclient.apollo.example.util.ServerUtil; +import com.lunarclient.apollo.module.totemcounter.TotemCounter; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModule; +import com.lunarclient.apollo.player.ApolloPlayer; +import com.lunarclient.apollo.recipients.Recipients; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityResurrectEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class TotemCounterApiExample extends TotemCounterExample implements Listener { + + private final TotemCounterModule totemCounterModule = Apollo.getModuleManager().getModule(TotemCounterModule.class); + + private final Map totemPops = new ConcurrentHashMap<>(); + + public TotemCounterApiExample() { + if (ServerUtil.hasEntityResurrectEvent()) { + Bukkit.getPluginManager().registerEvents(this, ApolloExamplePlugin.getInstance()); + } + } + + @Override + public void overrideTotemCounterExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + this.totemCounterModule.overrideTotemCounter(apolloPlayer, TotemCounter.builder() + .playerUuid(viewer.getUniqueId()) + .pops(3) + .build() + ); + }); + } + + @Override + public void overrideTotemCountersExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + List totemCounters = Bukkit.getOnlinePlayers() + .stream().map(player -> TotemCounter.builder() + .playerUuid(player.getUniqueId()) + .pops(2) + .build()) + .collect(Collectors.toList()); + + this.totemCounterModule.overrideTotemCounters(apolloPlayer, totemCounters); + }); + } + + @Override + public void resetTotemCounterExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.totemCounterModule.resetTotemCounter(apolloPlayer, viewer.getUniqueId())); + } + + @Override + public void resetTotemCountersExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(this.totemCounterModule::resetTotemCounters); + } + + @Override + public void setDisableLocalTracking(boolean value) { + this.totemCounterModule.getOptions().set(TotemCounterModule.DISABLE_LOCAL_TRACKING, value); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onEntityResurrect(EntityResurrectEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + + Player player = (Player) event.getEntity(); + int pops = this.totemPops.merge(player.getUniqueId(), 1, Integer::sum); + + // Pops are absolute, send the new total instead of an increment + this.totemCounterModule.overrideTotemCounter(Recipients.ofEveryone(), TotemCounter.builder() + .playerUuid(player.getUniqueId()) + .pops(pops) + .build() + ); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onPlayerDeath(PlayerDeathEvent event) { + this.resetTotemPops(event.getEntity()); + } + + @EventHandler + private void onPlayerQuit(PlayerQuitEvent event) { + this.resetTotemPops(event.getPlayer()); + } + + private void resetTotemPops(Player player) { + if (this.totemPops.remove(player.getUniqueId()) != null) { + this.totemCounterModule.resetTotemCounter(Recipients.ofEveryone(), player.getUniqueId()); + } + } + +} diff --git a/example/bukkit/api/src/main/resources/plugin.yml b/example/bukkit/api/src/main/resources/plugin.yml index 9ac047c9..db41169d 100644 --- a/example/bukkit/api/src/main/resources/plugin.yml +++ b/example/bukkit/api/src/main/resources/plugin.yml @@ -76,6 +76,8 @@ commands: description: "Titles!" tntcountdown: description: "TNT Countdown!" + totemcounter: + description: "Totem Counter!" transfer: description: "Transfer!" vignette: diff --git a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/ApolloExamplePlugin.java b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/ApolloExamplePlugin.java index a116a259..a341047e 100644 --- a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/ApolloExamplePlugin.java +++ b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/ApolloExamplePlugin.java @@ -55,6 +55,7 @@ import com.lunarclient.apollo.example.command.TebexCommand; import com.lunarclient.apollo.example.command.TitleCommand; import com.lunarclient.apollo.example.command.TntCountdownCommand; +import com.lunarclient.apollo.example.command.TotemCounterCommand; import com.lunarclient.apollo.example.command.TransferCommand; import com.lunarclient.apollo.example.command.VignetteCommand; import com.lunarclient.apollo.example.command.WaypointCommand; @@ -89,6 +90,7 @@ import com.lunarclient.apollo.example.module.impl.TebexExample; import com.lunarclient.apollo.example.module.impl.TitleExample; import com.lunarclient.apollo.example.module.impl.TntCountdownExample; +import com.lunarclient.apollo.example.module.impl.TotemCounterExample; import com.lunarclient.apollo.example.module.impl.TransferExample; import com.lunarclient.apollo.example.module.impl.VignetteExample; import com.lunarclient.apollo.example.module.impl.WaypointExample; @@ -137,6 +139,7 @@ public abstract class ApolloExamplePlugin extends JavaPlugin { private TebexExample tebexExample; private TitleExample titleExample; private TntCountdownExample tntCountdownExample; + private TotemCounterExample totemCounterExample; private TransferExample transferExample; private VignetteExample vignetteExample; private WaypointExample waypointExample; @@ -204,6 +207,7 @@ private void registerCommonCommands() { this.getCommand("tebex").setExecutor(new TebexCommand()); this.getCommand("title").setExecutor(new TitleCommand()); this.getCommand("tntcountdown").setExecutor(new TntCountdownCommand()); + this.getCommand("totemcounter").setExecutor(new TotemCounterCommand()); this.getCommand("transfer").setExecutor(new TransferCommand()); this.getCommand("vignette").setExecutor(new VignetteCommand()); this.getCommand("waypoint").setExecutor(new WaypointCommand()); diff --git a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/TotemCounterCommand.java b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/TotemCounterCommand.java new file mode 100644 index 00000000..667cf84e --- /dev/null +++ b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/TotemCounterCommand.java @@ -0,0 +1,94 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.example.command; + +import com.lunarclient.apollo.example.ApolloExamplePlugin; +import com.lunarclient.apollo.example.module.impl.TotemCounterExample; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public class TotemCounterCommand implements CommandExecutor { + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if (!(sender instanceof Player)) { + sender.sendMessage("Player only!"); + return true; + } + + Player player = (Player) sender; + TotemCounterExample totemCounterExample = ApolloExamplePlugin.getInstance().getTotemCounterExample(); + + if (args.length == 2 && args[0].equalsIgnoreCase("disableLocalTracking")) { + boolean value = Boolean.parseBoolean(args[1]); + totemCounterExample.setDisableLocalTracking(value); + + player.sendMessage("Disable local tracking has been set to " + value); + return true; + } + + if (args.length != 1) { + player.sendMessage("Usage: /totemcounter "); + player.sendMessage("Usage: /totemcounter "); + return true; + } + + switch (args[0].toLowerCase()) { + case "override": { + totemCounterExample.overrideTotemCounterExample(player); + player.sendMessage("Overriding totem counter...."); + break; + } + + case "overrideall": { + totemCounterExample.overrideTotemCountersExample(player); + player.sendMessage("Overriding totem counters...."); + break; + } + + case "reset": { + totemCounterExample.resetTotemCounterExample(player); + player.sendMessage("Resetting totem counter...."); + break; + } + + case "clear": { + totemCounterExample.resetTotemCountersExample(player); + player.sendMessage("Clearing totem counters..."); + break; + } + + default: { + player.sendMessage("Usage: /totemcounter "); + player.sendMessage("Usage: /totemcounter "); + break; + } + } + + return true; + } +} diff --git a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/TotemCounterExample.java b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/TotemCounterExample.java new file mode 100644 index 00000000..766f13f5 --- /dev/null +++ b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/TotemCounterExample.java @@ -0,0 +1,41 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.example.module.impl; + +import com.lunarclient.apollo.example.module.ApolloModuleExample; +import org.bukkit.entity.Player; + +public abstract class TotemCounterExample extends ApolloModuleExample { + + public abstract void overrideTotemCounterExample(Player viewer); + + public abstract void overrideTotemCountersExample(Player viewer); + + public abstract void resetTotemCounterExample(Player viewer); + + public abstract void resetTotemCountersExample(Player viewer); + + public abstract void setDisableLocalTracking(boolean value); + +} diff --git a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/util/ServerUtil.java b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/util/ServerUtil.java index f96c8568..6280e66e 100644 --- a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/util/ServerUtil.java +++ b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/util/ServerUtil.java @@ -34,6 +34,15 @@ public static boolean isFolia() { } } + public static boolean hasEntityResurrectEvent() { + try { + Class.forName("org.bukkit.event.entity.EntityResurrectEvent"); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + private ServerUtil() { } diff --git a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/ApolloJsonExamplePlatform.java b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/ApolloJsonExamplePlatform.java index 22a99601..0c84c89f 100644 --- a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/ApolloJsonExamplePlatform.java +++ b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/ApolloJsonExamplePlatform.java @@ -55,6 +55,7 @@ import com.lunarclient.apollo.example.json.module.TebexJsonExample; import com.lunarclient.apollo.example.json.module.TitleJsonExample; import com.lunarclient.apollo.example.json.module.TntCountdownJsonExample; +import com.lunarclient.apollo.example.json.module.TotemCounterJsonExample; import com.lunarclient.apollo.example.json.module.TransferJsonExample; import com.lunarclient.apollo.example.json.module.VignetteJsonExample; import com.lunarclient.apollo.example.json.module.WaypointJsonExample; @@ -102,6 +103,7 @@ public void registerModuleExamples() { this.setTebexExample(new TebexJsonExample()); this.setTitleExample(new TitleJsonExample()); this.setTntCountdownExample(new TntCountdownJsonExample()); + this.setTotemCounterExample(new TotemCounterJsonExample()); this.setTransferExample(new TransferJsonExample()); this.setVignetteExample(new VignetteJsonExample()); this.setWaypointExample(new WaypointJsonExample()); diff --git a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/TotemCounterJsonExample.java b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/TotemCounterJsonExample.java new file mode 100644 index 00000000..c5caf24c --- /dev/null +++ b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/TotemCounterJsonExample.java @@ -0,0 +1,167 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.example.json.module; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.lunarclient.apollo.example.ApolloExamplePlugin; +import com.lunarclient.apollo.example.json.util.JsonPacketUtil; +import com.lunarclient.apollo.example.json.util.JsonUtil; +import com.lunarclient.apollo.example.module.impl.TotemCounterExample; +import com.lunarclient.apollo.example.util.ServerUtil; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityResurrectEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class TotemCounterJsonExample extends TotemCounterExample implements Listener { + + private final Map totemPops = new ConcurrentHashMap<>(); + + public TotemCounterJsonExample() { + if (ServerUtil.hasEntityResurrectEvent()) { + Bukkit.getPluginManager().registerEvents(this, ApolloExamplePlugin.getInstance()); + } + } + + @Override + public void overrideTotemCounterExample(Player viewer) { + JsonObject totemCounter = new JsonObject(); + totemCounter.add("player_uuid", JsonUtil.createUuidObject(viewer.getUniqueId())); + totemCounter.addProperty("pops", 3); + + JsonArray totemCounters = new JsonArray(); + totemCounters.add(totemCounter); + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.OverrideTotemCountersMessage"); + message.add("totem_counters", totemCounters); + + JsonPacketUtil.sendPacket(viewer, message); + } + + @Override + public void overrideTotemCountersExample(Player viewer) { + JsonArray totemCounters = new JsonArray(); + + for (Player player : Bukkit.getOnlinePlayers()) { + JsonObject totemCounter = new JsonObject(); + totemCounter.add("player_uuid", JsonUtil.createUuidObject(player.getUniqueId())); + totemCounter.addProperty("pops", 2); + + totemCounters.add(totemCounter); + } + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.OverrideTotemCountersMessage"); + message.add("totem_counters", totemCounters); + + JsonPacketUtil.sendPacket(viewer, message); + } + + @Override + public void resetTotemCounterExample(Player viewer) { + JsonArray playerUuids = new JsonArray(); + playerUuids.add(JsonUtil.createUuidObject(viewer.getUniqueId())); + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.ResetTotemCounterMessage"); + message.add("player_uuids", playerUuids); + + JsonPacketUtil.sendPacket(viewer, message); + } + + @Override + public void resetTotemCountersExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.ResetTotemCountersMessage"); + + JsonPacketUtil.sendPacket(viewer, message); + } + + @Override + public void setDisableLocalTracking(boolean value) { + Map properties = new HashMap<>(); + properties.put("disable-local-tracking", value); + + JsonObject message = JsonUtil.createEnableModuleObjectWithType("totem_counter", properties); + JsonPacketUtil.broadcastPacket(message); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onEntityResurrect(EntityResurrectEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + + Player player = (Player) event.getEntity(); + int pops = this.totemPops.merge(player.getUniqueId(), 1, Integer::sum); + + // Pops are absolute, send the new total instead of an increment + JsonObject totemCounter = new JsonObject(); + totemCounter.add("player_uuid", JsonUtil.createUuidObject(player.getUniqueId())); + totemCounter.addProperty("pops", pops); + + JsonArray totemCounters = new JsonArray(); + totemCounters.add(totemCounter); + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.OverrideTotemCountersMessage"); + message.add("totem_counters", totemCounters); + + JsonPacketUtil.broadcastPacket(message); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onPlayerDeath(PlayerDeathEvent event) { + this.resetTotemPops(event.getEntity()); + } + + @EventHandler + private void onPlayerQuit(PlayerQuitEvent event) { + this.resetTotemPops(event.getPlayer()); + } + + private void resetTotemPops(Player player) { + if (this.totemPops.remove(player.getUniqueId()) != null) { + JsonArray playerUuids = new JsonArray(); + playerUuids.add(JsonUtil.createUuidObject(player.getUniqueId())); + + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.totemcounter.v1.ResetTotemCounterMessage"); + message.add("player_uuids", playerUuids); + + JsonPacketUtil.broadcastPacket(message); + } + } + +} diff --git a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/util/JsonPacketUtil.java b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/util/JsonPacketUtil.java index 59733a24..38c4b260 100644 --- a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/util/JsonPacketUtil.java +++ b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/util/JsonPacketUtil.java @@ -42,7 +42,7 @@ public final class JsonPacketUtil { private static final List APOLLO_MODULES = Arrays.asList("auto_text_hotkey", "beam", "border", "chat", "colored_fire", "combat", "cooldown", "cosmetic", "entity", "glint", "glow", "hologram", "inventory", "limb", "marker", "mod_setting", "nametag", "nick_hider", "notification", "pay_now", "packet_enrichment", - "rich_presence", "saturation", "server_link", "server_rule", "staff_mod", "stopwatch", "team", "tebex", "title", "tnt_countdown", "transfer", "vignette", "waypoint" + "rich_presence", "saturation", "server_link", "server_rule", "staff_mod", "stopwatch", "team", "tebex", "title", "tnt_countdown", "totem_counter", "transfer", "vignette", "waypoint" ); // Module Id -> Option key -> Object @@ -79,6 +79,7 @@ public final class JsonPacketUtil { CONFIG_MODULE_PROPERTIES.put("server_rule", "crystal-optimizer", false); CONFIG_MODULE_PROPERTIES.put("tnt_countdown", "tnt-ticks", 80); CONFIG_MODULE_PROPERTIES.put("title", "clear-title-on-server-switch", false); + CONFIG_MODULE_PROPERTIES.put("totem_counter", "disable-local-tracking", false); CONFIG_MODULE_PROPERTIES.put("waypoint", "server-handles-waypoints", false); } diff --git a/example/bukkit/json/src/main/resources/plugin.yml b/example/bukkit/json/src/main/resources/plugin.yml index 64cd0c62..f6a3c0c8 100644 --- a/example/bukkit/json/src/main/resources/plugin.yml +++ b/example/bukkit/json/src/main/resources/plugin.yml @@ -72,6 +72,8 @@ commands: description: "Titles!" tntcountdown: description: "TNT Countdown!" + totemcounter: + description: "Totem Counter!" transfer: description: "Transfer!" vignette: diff --git a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/ApolloProtoExamplePlatform.java b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/ApolloProtoExamplePlatform.java index 680a71e2..09d3a28e 100644 --- a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/ApolloProtoExamplePlatform.java +++ b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/ApolloProtoExamplePlatform.java @@ -55,6 +55,7 @@ import com.lunarclient.apollo.example.proto.module.TebexProtoExample; import com.lunarclient.apollo.example.proto.module.TitleProtoExample; import com.lunarclient.apollo.example.proto.module.TntCountdownProtoExample; +import com.lunarclient.apollo.example.proto.module.TotemCounterProtoExample; import com.lunarclient.apollo.example.proto.module.TransferProtoExample; import com.lunarclient.apollo.example.proto.module.VignetteProtoExample; import com.lunarclient.apollo.example.proto.module.WaypointProtoExample; @@ -102,6 +103,7 @@ public void registerModuleExamples() { this.setTebexExample(new TebexProtoExample()); this.setTitleExample(new TitleProtoExample()); this.setTntCountdownExample(new TntCountdownProtoExample()); + this.setTotemCounterExample(new TotemCounterProtoExample()); this.setTransferExample(new TransferProtoExample()); this.setVignetteExample(new VignetteProtoExample()); this.setWaypointExample(new WaypointProtoExample()); diff --git a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/TotemCounterProtoExample.java b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/TotemCounterProtoExample.java new file mode 100644 index 00000000..255b36bc --- /dev/null +++ b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/TotemCounterProtoExample.java @@ -0,0 +1,158 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.example.proto.module; + +import com.google.protobuf.Value; +import com.lunarclient.apollo.configurable.v1.ConfigurableSettings; +import com.lunarclient.apollo.example.ApolloExamplePlugin; +import com.lunarclient.apollo.example.module.impl.TotemCounterExample; +import com.lunarclient.apollo.example.proto.util.ProtobufPacketUtil; +import com.lunarclient.apollo.example.proto.util.ProtobufUtil; +import com.lunarclient.apollo.example.util.ServerUtil; +import com.lunarclient.apollo.totemcounter.v1.OverrideTotemCountersMessage; +import com.lunarclient.apollo.totemcounter.v1.ResetTotemCounterMessage; +import com.lunarclient.apollo.totemcounter.v1.ResetTotemCountersMessage; +import com.lunarclient.apollo.totemcounter.v1.TotemCounter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.entity.EntityResurrectEvent; +import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class TotemCounterProtoExample extends TotemCounterExample implements Listener { + + private final Map totemPops = new ConcurrentHashMap<>(); + + public TotemCounterProtoExample() { + if (ServerUtil.hasEntityResurrectEvent()) { + Bukkit.getPluginManager().registerEvents(this, ApolloExamplePlugin.getInstance()); + } + } + + @Override + public void overrideTotemCounterExample(Player viewer) { + TotemCounter totemCounter = TotemCounter.newBuilder() + .setPlayerUuid(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .setPops(3) + .build(); + + OverrideTotemCountersMessage message = OverrideTotemCountersMessage.newBuilder() + .addTotemCounters(totemCounter) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } + + @Override + public void overrideTotemCountersExample(Player viewer) { + List totemCounters = Bukkit.getOnlinePlayers() + .stream().map(player -> TotemCounter.newBuilder() + .setPlayerUuid(ProtobufUtil.createUuidProto(player.getUniqueId())) + .setPops(2) + .build()) + .collect(Collectors.toList()); + + OverrideTotemCountersMessage message = OverrideTotemCountersMessage.newBuilder() + .addAllTotemCounters(totemCounters) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } + + @Override + public void resetTotemCounterExample(Player viewer) { + ResetTotemCounterMessage message = ResetTotemCounterMessage.newBuilder() + .addPlayerUuids(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } + + @Override + public void resetTotemCountersExample(Player viewer) { + ResetTotemCountersMessage message = ResetTotemCountersMessage.getDefaultInstance(); + ProtobufPacketUtil.sendPacket(viewer, message); + } + + @Override + public void setDisableLocalTracking(boolean value) { + Map properties = new HashMap<>(); + properties.put("disable-local-tracking", Value.newBuilder().setBoolValue(value).build()); + + ConfigurableSettings settings = ProtobufPacketUtil.createModuleMessage("totem_counter", properties); + ProtobufPacketUtil.broadcastPacket(settings); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onEntityResurrect(EntityResurrectEvent event) { + if (!(event.getEntity() instanceof Player)) { + return; + } + + Player player = (Player) event.getEntity(); + int pops = this.totemPops.merge(player.getUniqueId(), 1, Integer::sum); + + // Pops are absolute, send the new total instead of an increment + TotemCounter totemCounter = TotemCounter.newBuilder() + .setPlayerUuid(ProtobufUtil.createUuidProto(player.getUniqueId())) + .setPops(pops) + .build(); + + OverrideTotemCountersMessage message = OverrideTotemCountersMessage.newBuilder() + .addTotemCounters(totemCounter) + .build(); + + ProtobufPacketUtil.broadcastPacket(message); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + private void onPlayerDeath(PlayerDeathEvent event) { + this.resetTotemPops(event.getEntity()); + } + + @EventHandler + private void onPlayerQuit(PlayerQuitEvent event) { + this.resetTotemPops(event.getPlayer()); + } + + private void resetTotemPops(Player player) { + if (this.totemPops.remove(player.getUniqueId()) != null) { + ResetTotemCounterMessage message = ResetTotemCounterMessage.newBuilder() + .addPlayerUuids(ProtobufUtil.createUuidProto(player.getUniqueId())) + .build(); + + ProtobufPacketUtil.broadcastPacket(message); + } + } + +} diff --git a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/util/ProtobufPacketUtil.java b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/util/ProtobufPacketUtil.java index b5171f58..7b74c74b 100644 --- a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/util/ProtobufPacketUtil.java +++ b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/util/ProtobufPacketUtil.java @@ -43,7 +43,7 @@ public final class ProtobufPacketUtil { private static final List APOLLO_MODULES = Arrays.asList("auto_text_hotkey", "beam", "border", "chat", "colored_fire", "combat", "cooldown", "cosmetic", "entity", "glint", "glow", "hologram", "inventory", "limb", "marker", "mod_setting", "nametag", "nick_hider", "notification", "pay_now", "packet_enrichment", - "rich_presence", "saturation", "server_link", "server_rule", "staff_mod", "stopwatch", "team", "tebex", "title", "tnt_countdown", "transfer", "vignette", "waypoint" + "rich_presence", "saturation", "server_link", "server_rule", "staff_mod", "stopwatch", "team", "tebex", "title", "tnt_countdown", "totem_counter", "transfer", "vignette", "waypoint" ); // Module Id -> Option key -> Value @@ -86,6 +86,7 @@ public final class ProtobufPacketUtil { CONFIG_MODULE_PROPERTIES.put("server_rule", "crystal-optimizer", Value.newBuilder().setBoolValue(false).build()); CONFIG_MODULE_PROPERTIES.put("tnt_countdown", "tnt-ticks", Value.newBuilder().setNumberValue(80).build()); CONFIG_MODULE_PROPERTIES.put("title", "clear-title-on-server-switch", Value.newBuilder().setBoolValue(false).build()); + CONFIG_MODULE_PROPERTIES.put("totem_counter", "disable-local-tracking", Value.newBuilder().setBoolValue(false).build()); CONFIG_MODULE_PROPERTIES.put("waypoint", "server-handles-waypoints", Value.newBuilder().setBoolValue(false).build()); } diff --git a/example/bukkit/proto/src/main/resources/plugin.yml b/example/bukkit/proto/src/main/resources/plugin.yml index da8661d0..8cb0cbeb 100644 --- a/example/bukkit/proto/src/main/resources/plugin.yml +++ b/example/bukkit/proto/src/main/resources/plugin.yml @@ -72,6 +72,8 @@ commands: description: "Titles!" tntcountdown: description: "TNT Countdown!" + totemcounter: + description: "Totem Counter!" transfer: description: "Transfer!" vignette: diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5099e64b..ba4c1777 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ geantyref = "1.3.11" idea = "1.1.7" jetbrains = "24.0.1" lombok = "1.18.38" -protobuf = "0.2.4" +protobuf = "0.2.5" gson = "2.10.1" shadow = "9.4.1" spotless = "8.4.0" diff --git a/platform/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java b/platform/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java index dd49d311..f3d83d56 100644 --- a/platform/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java +++ b/platform/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java @@ -90,6 +90,8 @@ import com.lunarclient.apollo.module.title.TitleModuleImpl; import com.lunarclient.apollo.module.tntcountdown.TntCountdownModule; import com.lunarclient.apollo.module.tntcountdown.TntCountdownModuleImpl; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModule; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModuleImpl; import com.lunarclient.apollo.module.transfer.TransferModule; import com.lunarclient.apollo.module.transfer.TransferModuleImpl; import com.lunarclient.apollo.module.vignette.VignetteModule; @@ -174,6 +176,7 @@ public void onEnable() { .addModule(TebexModule.class, new TebexModuleImpl()) .addModule(TitleModule.class, new TitleModuleImpl()) .addModule(TntCountdownModule.class, new TntCountdownModuleImpl()) + .addModule(TotemCounterModule.class, new TotemCounterModuleImpl()) .addModule(TransferModule.class, new TransferModuleImpl()) .addModule(VignetteModule.class, new VignetteModuleImpl()) .addModule(WaypointModule.class, new WaypointModuleImpl()); diff --git a/platform/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java b/platform/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java index 2c35eb66..9e349427 100644 --- a/platform/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java +++ b/platform/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java @@ -79,6 +79,8 @@ import com.lunarclient.apollo.module.tebex.TebexModuleImpl; import com.lunarclient.apollo.module.title.TitleModule; import com.lunarclient.apollo.module.title.TitleModuleImpl; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModule; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModuleImpl; import com.lunarclient.apollo.module.transfer.TransferModule; import com.lunarclient.apollo.module.transfer.TransferModuleImpl; import com.lunarclient.apollo.module.vignette.VignetteModule; @@ -153,6 +155,7 @@ public void onEnable() { .addModule(TeamModule.class, new TeamModuleImpl()) .addModule(TebexModule.class, new TebexModuleImpl()) .addModule(TitleModule.class, new TitleModuleImpl()) + .addModule(TotemCounterModule.class, new TotemCounterModuleImpl()) .addModule(TransferModule.class, new TransferModuleImpl()) .addModule(VignetteModule.class, new VignetteModuleImpl()) .addModule(WaypointModule.class, new WaypointModuleImpl()); diff --git a/platform/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java b/platform/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java index 1bf3caea..4ee2734b 100644 --- a/platform/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java +++ b/platform/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java @@ -87,6 +87,8 @@ import com.lunarclient.apollo.module.title.TitleModuleImpl; import com.lunarclient.apollo.module.tntcountdown.TntCountdownModule; import com.lunarclient.apollo.module.tntcountdown.TntCountdownModuleImpl; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModule; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModuleImpl; import com.lunarclient.apollo.module.transfer.TransferModule; import com.lunarclient.apollo.module.transfer.TransferModuleImpl; import com.lunarclient.apollo.module.vignette.VignetteModule; @@ -163,6 +165,7 @@ public void onEnable() { .addModule(TebexModule.class, new TebexModuleImpl()) .addModule(TitleModule.class, new TitleModuleImpl()) .addModule(TntCountdownModule.class, new TntCountdownModuleImpl()) + .addModule(TotemCounterModule.class, new TotemCounterModuleImpl()) .addModule(TransferModule.class, new TransferModuleImpl()) .addModule(VignetteModule.class, new VignetteModuleImpl()) .addModule(WaypointModule.class, new WaypointModuleImpl()); diff --git a/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java b/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java index 60ac7559..1c3a32e2 100644 --- a/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java +++ b/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java @@ -89,6 +89,8 @@ import com.lunarclient.apollo.module.title.TitleModuleImpl; import com.lunarclient.apollo.module.tntcountdown.TntCountdownModule; import com.lunarclient.apollo.module.tntcountdown.TntCountdownModuleImpl; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModule; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModuleImpl; import com.lunarclient.apollo.module.transfer.TransferModule; import com.lunarclient.apollo.module.transfer.TransferModuleImpl; import com.lunarclient.apollo.module.vignette.VignetteModule; @@ -198,6 +200,7 @@ public static void init(ApolloMinestomProperties properties) { .addModule(TebexModule.class, new TebexModuleImpl()) .addModule(TitleModule.class, new TitleModuleImpl()) .addModule(TntCountdownModule.class, new TntCountdownModuleImpl()) + .addModule(TotemCounterModule.class, new TotemCounterModuleImpl()) .addModule(TransferModule.class, new TransferModuleImpl()) .addModule(VignetteModule.class, new VignetteModuleImpl()) .addModule(WaypointModule.class, new WaypointModuleImpl()); diff --git a/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java b/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java index cacb9393..69bd2e43 100644 --- a/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java +++ b/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java @@ -79,6 +79,8 @@ import com.lunarclient.apollo.module.tebex.TebexModuleImpl; import com.lunarclient.apollo.module.title.TitleModule; import com.lunarclient.apollo.module.title.TitleModuleImpl; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModule; +import com.lunarclient.apollo.module.totemcounter.TotemCounterModuleImpl; import com.lunarclient.apollo.module.transfer.TransferModule; import com.lunarclient.apollo.module.transfer.TransferModuleImpl; import com.lunarclient.apollo.module.vignette.VignetteModule; @@ -236,6 +238,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) { .addModule(TeamModule.class, new TeamModuleImpl()) .addModule(TebexModule.class, new TebexModuleImpl()) .addModule(TitleModule.class, new TitleModuleImpl()) + .addModule(TotemCounterModule.class, new TotemCounterModuleImpl()) .addModule(TransferModule.class, new TransferModuleImpl()) .addModule(VignetteModule.class, new VignetteModuleImpl()) .addModule(WaypointModule.class, new WaypointModuleImpl()); From 14fabb403b3b5c42a9fb643af1bac165c12af47e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Bu=C4=8Dari=C4=87?= Date: Wed, 7 Oct 2026 17:57:01 +0200 Subject: [PATCH 3/6] Feature - Private Mod Status API (#312) * Paginate Mod Status API and mark as Restricted Access * Remove temp deploy --- .github/workflows/deploy.yml | 2 +- .../ApolloUpdateModOptionEvent.java | 12 +- .../apollo/module/RestrictedAccess.java | 48 +++++ .../module/cosmetic/CosmeticModule.java | 4 + .../module/modsetting/ModOptionStatus.java | 57 ++++++ .../module/modsetting/ModSettingModule.java | 14 ++ .../module/modsetting/ModStatusRequest.java | 39 ++++ .../module/modsetting/ModStatusResponse.java | 54 ++++++ .../modsettings/ModSettingModuleImpl.java | 54 ++++++ .../player/ApolloPlayerManagerImpl.java | 12 -- docs/acceptable-use.mdx | 2 +- docs/developers/events.mdx | 2 + .../lightweight/json/roundtrip-packets.mdx | 16 ++ .../protobuf/roundtrip-packets.mdx | 38 ++++ docs/developers/modules.mdx | 2 + docs/developers/modules/inventory.mdx | 141 +++++++------- docs/developers/modules/modsetting.mdx | 66 +------ docs/developers/private-modules.mdx | 16 +- docs/developers/private-modules/_meta.json | 3 +- docs/developers/private-modules/modstatus.mdx | 181 ++++++++++++++++++ .../api/mods/ApolloModStatusExample.java | 30 +-- .../example/api/mods/ModStatusCommand.java | 34 ++-- .../api/module/InventoryApiExample.java | 17 +- .../api/module/ModSettingsApiExample.java | 20 ++ .../inventorybuttons/MinigameLayout.java | 149 +++++++------- .../example/command/ModSettingsCommand.java | 10 +- .../module/impl/ModSettingsExample.java | 2 + .../listener/ApolloRoundtripJsonListener.java | 16 ++ .../json/module/ModSettingsJsonExample.java | 18 ++ .../ApolloRoundtripProtoListener.java | 41 ++++ .../proto/module/ModSettingsProtoExample.java | 23 +++ gradle/libs.versions.toml | 2 +- 32 files changed, 871 insertions(+), 254 deletions(-) create mode 100644 api/src/main/java/com/lunarclient/apollo/module/RestrictedAccess.java create mode 100644 api/src/main/java/com/lunarclient/apollo/module/modsetting/ModOptionStatus.java create mode 100644 api/src/main/java/com/lunarclient/apollo/module/modsetting/ModStatusRequest.java create mode 100644 api/src/main/java/com/lunarclient/apollo/module/modsetting/ModStatusResponse.java create mode 100644 docs/developers/private-modules/modstatus.mdx diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 4a465fe7..f65bf2a7 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -41,7 +41,7 @@ jobs: fi - name: Gradle Publish - if: "${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/version/') || github.ref == 'refs/heads/feature/totem-counter-module' }}" + if: "${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/version/') }}" run: ./gradlew publish - name: Gradle Release diff --git a/api/src/main/java/com/lunarclient/apollo/event/modsetting/ApolloUpdateModOptionEvent.java b/api/src/main/java/com/lunarclient/apollo/event/modsetting/ApolloUpdateModOptionEvent.java index d8724a6d..0199fabb 100644 --- a/api/src/main/java/com/lunarclient/apollo/event/modsetting/ApolloUpdateModOptionEvent.java +++ b/api/src/main/java/com/lunarclient/apollo/event/modsetting/ApolloUpdateModOptionEvent.java @@ -24,17 +24,27 @@ package com.lunarclient.apollo.event.modsetting; import com.lunarclient.apollo.event.Event; +import com.lunarclient.apollo.module.RestrictedAccess; +import com.lunarclient.apollo.module.modsetting.ModSettingModule; import com.lunarclient.apollo.option.Option; import com.lunarclient.apollo.player.ApolloPlayer; import lombok.Value; import org.jetbrains.annotations.Nullable; /** - * Represents an event that is fired when an option is updated. + * Represents an event that is fired when a player's Lunar Client mod option is updated. + * + *

This event is fired for live updates only, not for the options listed in a + * {@link ModSettingModule#requestModStatus(ApolloPlayer)} response.

+ * + *

This event is part of the private Mod Status API of {@link ModSettingModule}. Lunar Client + * only reports mod status to servers that have been granted access, so this event is never + * fired on other servers.

* * @since 1.2.1 */ @Value +@RestrictedAccess public class ApolloUpdateModOptionEvent implements Event { /** diff --git a/api/src/main/java/com/lunarclient/apollo/module/RestrictedAccess.java b/api/src/main/java/com/lunarclient/apollo/module/RestrictedAccess.java new file mode 100644 index 00000000..46c68062 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/RestrictedAccess.java @@ -0,0 +1,48 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.module; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks access restricted Apollo API, either a whole module or part of a public module. + * + *

Restricted API only works on servers approved by the Lunar Client team. Lunar Client + * enforces this, so without approval the API does not throw, it just has no effect.

+ * + *

See Private Modules + * to request access.

+ * + * @since 1.3.0 + */ +@Documented +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.CLASS) +public @interface RestrictedAccess { + // Marker annotation. +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/cosmetic/CosmeticModule.java b/api/src/main/java/com/lunarclient/apollo/module/cosmetic/CosmeticModule.java index 45783a13..dd20a602 100644 --- a/api/src/main/java/com/lunarclient/apollo/module/cosmetic/CosmeticModule.java +++ b/api/src/main/java/com/lunarclient/apollo/module/cosmetic/CosmeticModule.java @@ -26,6 +26,7 @@ import com.lunarclient.apollo.common.location.ApolloBlockLocation; import com.lunarclient.apollo.module.ApolloModule; import com.lunarclient.apollo.module.ModuleDefinition; +import com.lunarclient.apollo.module.RestrictedAccess; import com.lunarclient.apollo.module.cosmetic.options.BodyOptions; import com.lunarclient.apollo.module.cosmetic.options.CloakOptions; import com.lunarclient.apollo.module.cosmetic.options.CosmeticOptions; @@ -41,8 +42,11 @@ /** * Represents the cosmetic module. * + *

Access to this module is {@link RestrictedAccess restricted}.

+ * * @since 1.2.6 */ +@RestrictedAccess @ApiStatus.NonExtendable @ModuleDefinition(id = "cosmetic", name = "Cosmetic") public abstract class CosmeticModule extends ApolloModule { diff --git a/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModOptionStatus.java b/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModOptionStatus.java new file mode 100644 index 00000000..a294baf5 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModOptionStatus.java @@ -0,0 +1,57 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.module.modsetting; + +import com.lunarclient.apollo.module.RestrictedAccess; +import com.lunarclient.apollo.option.Option; +import lombok.Builder; +import lombok.Getter; + +/** + * Represents the current value of a Lunar Client mod option. + * + * @since 1.3.0 + */ +@Getter +@Builder +@RestrictedAccess +public final class ModOptionStatus { + + /** + * Returns the mod {@link Option}. + * + * @return the option + * @since 1.3.0 + */ + Option option; + + /** + * Returns the current {@link Object} value of the option. + * + * @return the value + * @since 1.3.0 + */ + Object value; + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModSettingModule.java b/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModSettingModule.java index c166aed9..22fff0ce 100644 --- a/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModSettingModule.java +++ b/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModSettingModule.java @@ -27,6 +27,7 @@ import com.lunarclient.apollo.async.Future; import com.lunarclient.apollo.module.ApolloModule; import com.lunarclient.apollo.module.ModuleDefinition; +import com.lunarclient.apollo.module.RestrictedAccess; import com.lunarclient.apollo.option.Option; import com.lunarclient.apollo.player.ApolloPlayer; import com.lunarclient.apollo.util.ConfigTarget; @@ -65,6 +66,7 @@ public boolean isClientNotify() { * @return the value of the option * @since 1.2.1 */ + @RestrictedAccess public abstract > T getStatus(@NotNull ApolloPlayer player, @NonNull C option); /** @@ -76,4 +78,16 @@ public boolean isClientNotify() { */ public abstract Future requestInstalledMods(ApolloPlayer player); + /** + * Sends the {@link ModStatusRequest} to the {@link ApolloPlayer}. + * + *

The response also updates {@link #getStatus(ApolloPlayer, Option)}.

+ * + * @param player the player + * @return future to be listened to for errors/success + * @since 1.3.0 + */ + @RestrictedAccess + public abstract Future requestModStatus(ApolloPlayer player); + } diff --git a/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModStatusRequest.java b/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModStatusRequest.java new file mode 100644 index 00000000..1c5b635b --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModStatusRequest.java @@ -0,0 +1,39 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.module.modsetting; + +import com.lunarclient.apollo.module.RestrictedAccess; +import com.lunarclient.apollo.roundtrip.ApolloRequest; +import lombok.Builder; + +/** + * Represents the mod status request. + * + * @since 1.3.0 + */ +@Builder +@RestrictedAccess +public final class ModStatusRequest extends ApolloRequest { + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModStatusResponse.java b/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModStatusResponse.java new file mode 100644 index 00000000..f31373ab --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/modsetting/ModStatusResponse.java @@ -0,0 +1,54 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.module.modsetting; + +import com.lunarclient.apollo.module.RestrictedAccess; +import com.lunarclient.apollo.roundtrip.pagination.ApolloPaginatedResponse; +import java.util.List; +import java.util.UUID; +import lombok.Getter; +import lombok.experimental.SuperBuilder; + +/** + * Represents the mod status response. + * + *

The elements are the mod options the player has changed from their default + * value. Any option that is not listed is at its default value.

+ * + * @since 1.3.0 + */ +@Getter +@SuperBuilder +@RestrictedAccess +public final class ModStatusResponse extends ApolloPaginatedResponse { + + @Override + public ApolloPaginatedResponse combine(UUID packetId, List elements) { + return ModStatusResponse.builder() + .packetId(packetId) + .elements(elements) + .build(); + } + +} diff --git a/common/src/main/java/com/lunarclient/apollo/module/modsettings/ModSettingModuleImpl.java b/common/src/main/java/com/lunarclient/apollo/module/modsettings/ModSettingModuleImpl.java index 50e1c963..278b33ca 100644 --- a/common/src/main/java/com/lunarclient/apollo/module/modsettings/ModSettingModuleImpl.java +++ b/common/src/main/java/com/lunarclient/apollo/module/modsettings/ModSettingModuleImpl.java @@ -39,12 +39,16 @@ import com.lunarclient.apollo.modsetting.v1.Mod; import com.lunarclient.apollo.module.modsetting.InstalledModsRequest; import com.lunarclient.apollo.module.modsetting.InstalledModsResponse; +import com.lunarclient.apollo.module.modsetting.ModOptionStatus; import com.lunarclient.apollo.module.modsetting.ModSettingModule; +import com.lunarclient.apollo.module.modsetting.ModStatusRequest; +import com.lunarclient.apollo.module.modsetting.ModStatusResponse; import com.lunarclient.apollo.network.NetworkOptions; import com.lunarclient.apollo.option.Option; import com.lunarclient.apollo.option.StatusOptionsImpl; import com.lunarclient.apollo.player.AbstractApolloPlayer; import com.lunarclient.apollo.player.ApolloPlayer; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; @@ -89,6 +93,17 @@ public Future requestInstalledMods(@NotNull ApolloPlayer return ((AbstractApolloPlayer) player).sendRoundTripPacket(request, requestProto); } + @Override + public Future requestModStatus(@NotNull ApolloPlayer player) { + ModStatusRequest request = ModStatusRequest.builder().build(); + + com.lunarclient.apollo.modsetting.v1.ModStatusRequest requestProto = com.lunarclient.apollo.modsetting.v1.ModStatusRequest.newBuilder() + .setRequestId(ByteString.copyFromUtf8(request.getRequestId().toString())) + .build(); + + return ((AbstractApolloPlayer) player).sendRoundTripPacket(request, requestProto); + } + private void onReceivePacket(ApolloReceivePacketEvent event) { ApolloPlayer player = event.getPlayer(); Any any = event.getPacket(); @@ -112,6 +127,17 @@ private void onReceivePacket(ApolloReceivePacketEvent event) { ApolloManager.getRoundtripManager().handleResponse(response); }); + + event.unpack(com.lunarclient.apollo.modsetting.v1.ModStatusResponse.class).ifPresent(packet -> { + ModStatusResponse response = ModStatusResponse.builder() + .packetId(UUID.fromString(packet.getRequestId().toStringUtf8())) + .page(packet.getPage()) + .totalPages(packet.getTotalPages()) + .elements(this.updateModStatus(player, packet)) + .build(); + + ApolloManager.getRoundtripManager().handleResponse(response); + }); } private LunarClientMod fromProtobuf(LunarClientModType type, Mod mod) { @@ -188,4 +214,32 @@ public void updateOptions(ApolloPlayer player, Map properties, bo } } + private List updateModStatus(ApolloPlayer player, com.lunarclient.apollo.modsetting.v1.ModStatusResponse packet) { + StatusOptionsImpl statusOptions = ApolloManager.getModsManager().getPlayerOptions(); + + if (packet.getPage() == 0) { + statusOptions.getPlayerOptions().remove(player.getUniqueId()); + } + + List elements = new ArrayList<>(); + for (com.lunarclient.apollo.modsetting.v1.ModOptionStatus status : packet.getModOptionsList()) { + Option option = statusOptions.getRegistry().get(status.getKey()); + + // Option exists on the client but doesn't exist in the API yet. + if (option == null) { + continue; + } + + Object value = NetworkOptions.unwrapValue(status.getValue(), option.getTypeToken().getType()); + statusOptions.set(player, option, value); + + elements.add(ModOptionStatus.builder() + .option(option) + .value(value) + .build()); + } + + return elements; + } + } diff --git a/common/src/main/java/com/lunarclient/apollo/player/ApolloPlayerManagerImpl.java b/common/src/main/java/com/lunarclient/apollo/player/ApolloPlayerManagerImpl.java index 329c519c..8e2af840 100644 --- a/common/src/main/java/com/lunarclient/apollo/player/ApolloPlayerManagerImpl.java +++ b/common/src/main/java/com/lunarclient/apollo/player/ApolloPlayerManagerImpl.java @@ -23,7 +23,6 @@ */ package com.lunarclient.apollo.player; -import com.google.protobuf.Value; import com.lunarclient.apollo.Apollo; import com.lunarclient.apollo.client.version.LunarClientVersion; import com.lunarclient.apollo.client.version.MinecraftVersion; @@ -31,8 +30,6 @@ import com.lunarclient.apollo.event.player.ApolloPlayerHandshakeEvent; import com.lunarclient.apollo.event.player.ApolloRegisterPlayerEvent; import com.lunarclient.apollo.event.player.ApolloUnregisterPlayerEvent; -import com.lunarclient.apollo.module.modsetting.ModSettingModule; -import com.lunarclient.apollo.module.modsettings.ModSettingModuleImpl; import com.lunarclient.apollo.module.paynow.PayNowEmbeddedCheckoutSupport; import com.lunarclient.apollo.module.tebex.TebexEmbeddedCheckoutSupport; import com.lunarclient.apollo.network.NetworkOptions; @@ -149,15 +146,6 @@ public void handlePlayerHandshake(@NotNull ApolloPlayer player, @NotNull PlayerH apolloPlayer.setTebexEmbeddedCheckoutSupport(tebexEmbeddedCheckoutSupport); apolloPlayer.setPayNowEmbeddedCheckoutSupport(payNowEmbeddedCheckoutSupport); - Map modStatus = message.getModStatusMap(); - if (!modStatus.isEmpty()) { - ModSettingModuleImpl modSettingModule = (ModSettingModuleImpl) Apollo.getModuleManager().getModule(ModSettingModule.class); - - if (modSettingModule.isEnabled()) { - modSettingModule.updateOptions(apolloPlayer, modStatus, false); - } - } - ApolloPlayerHandshakeEvent event = new ApolloPlayerHandshakeEvent( player, minecraftVersion, lunarClientVersion, new ArrayList<>(), tebexEmbeddedCheckoutSupport, payNowEmbeddedCheckoutSupport diff --git a/docs/acceptable-use.mdx b/docs/acceptable-use.mdx index 49226e1c..e640360a 100644 --- a/docs/acceptable-use.mdx +++ b/docs/acceptable-use.mdx @@ -13,7 +13,7 @@ Apollo includes a wide range of publicly available modules that can be used by a The intent of Apollo is to encourage servers to integrate directly with Lunar Client to create better player experiences. ## Private & Future Modules -Apollo includes [private modules](/apollo/developers/private-modules) that require additional approval before use. +Apollo includes [private modules and features](/apollo/developers/private-modules) that require additional approval before use. We typically reserve private modules for features that: * Something that requires backing infrastructure that we're unable to provide for free. diff --git a/docs/developers/events.mdx b/docs/developers/events.mdx index 358b356a..5287787e 100644 --- a/docs/developers/events.mdx +++ b/docs/developers/events.mdx @@ -186,6 +186,8 @@ _Called when a Lunar Client Mod option is updated._ | `Option option` | The option that was updated. | | `Object value` | The new value of the option. | +This event is part of the private [Mod Status API](/apollo/developers/private-modules/modstatus) and is only called on servers that have been granted access. +
diff --git a/docs/developers/lightweight/json/roundtrip-packets.mdx b/docs/developers/lightweight/json/roundtrip-packets.mdx index cd9c9666..a4966284 100644 --- a/docs/developers/lightweight/json/roundtrip-packets.mdx +++ b/docs/developers/lightweight/json/roundtrip-packets.mdx @@ -57,6 +57,9 @@ public class ApolloRoundtripJsonListener implements PluginMessageListener { } else if ("lunarclient.apollo.modsetting.v1.InstalledModsResponse".equals(type)) { UUID requestId = UUID.fromString(payload.get("request_id").getAsString().replace("+", "-")); this.parseModGroups(requestId, payload); + } else if ("lunarclient.apollo.modsetting.v1.ModStatusResponse".equals(type)) { + UUID requestId = UUID.fromString(payload.get("request_id").getAsString().replace("+", "-")); + this.parseModStatus(requestId, payload); } } @@ -124,6 +127,19 @@ public class ApolloRoundtripJsonListener implements PluginMessageListener { this.handlePage(requestId, accumulated, response); } + private void parseModStatus(UUID requestId, JsonObject response) { + List accumulated = this.paginatedAccumulator.computeIfAbsent(requestId, k -> new ArrayList<>()); + + JsonArray modOptions = response.getAsJsonArray("mod_options"); + if (modOptions != null) { + for (JsonElement option : modOptions) { + accumulated.add(option.getAsJsonObject()); + } + } + + this.handlePage(requestId, accumulated, response); + } + private void handlePage(UUID requestId, List accumulated, JsonObject response) { int page = response.has("page") ? response.get("page").getAsInt() : 0; int totalPages = response.has("total_pages") ? response.get("total_pages").getAsInt() : 1; diff --git a/docs/developers/lightweight/protobuf/roundtrip-packets.mdx b/docs/developers/lightweight/protobuf/roundtrip-packets.mdx index eacbddde..f486492d 100644 --- a/docs/developers/lightweight/protobuf/roundtrip-packets.mdx +++ b/docs/developers/lightweight/protobuf/roundtrip-packets.mdx @@ -15,6 +15,8 @@ public class ApolloRoundtripProtoListener implements PluginMessageListener { private final Map>> roundTripPacketFutures = new ConcurrentHashMap<>(); private final Map>> paginatedFutures = new ConcurrentHashMap<>(); private final Map> paginatedAccumulator = new ConcurrentHashMap<>(); + private final Map>> modStatusFutures = new ConcurrentHashMap<>(); + private final Map> modStatusAccumulator = new ConcurrentHashMap<>(); private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); public ApolloRoundtripProtoListener(ApolloExamplePlugin plugin) { @@ -39,6 +41,10 @@ public class ApolloRoundtripProtoListener implements PluginMessageListener { InstalledModsResponse message = any.unpack(InstalledModsResponse.class); UUID requestId = UUID.fromString(message.getRequestId().toStringUtf8()); this.handlePagedResponse(requestId, message); + } else if (any.is(ModStatusResponse.class)) { + ModStatusResponse message = any.unpack(ModStatusResponse.class); + UUID requestId = UUID.fromString(message.getRequestId().toStringUtf8()); + this.handleModStatusPage(requestId, message); } } catch (InvalidProtocolBufferException e) { @@ -85,6 +91,38 @@ public class ApolloRoundtripProtoListener implements PluginMessageListener { return future; } + public CompletableFuture> sendModStatusRequest(Player player, UUID requestId, ModStatusRequest request) { + ProtobufPacketUtil.sendPacket(player, request); + + CompletableFuture> future = new CompletableFuture<>(); + this.modStatusFutures.put(requestId, future); + + ScheduledFuture timeoutTask = this.executorService.schedule(() -> + future.completeExceptionally(new TimeoutException("Response timed out")), + 10, TimeUnit.SECONDS + ); + + future.whenComplete((result, throwable) -> { + timeoutTask.cancel(false); + this.modStatusAccumulator.remove(requestId); + }); + + return future; + } + + private void handleModStatusPage(UUID requestId, ModStatusResponse response) { + List accumulated = this.modStatusAccumulator.computeIfAbsent(requestId, k -> new ArrayList<>()); + accumulated.addAll(response.getModOptionsList()); + + if (response.getPage() == response.getTotalPages() - 1) { + this.modStatusAccumulator.remove(requestId); + CompletableFuture> future = this.modStatusFutures.remove(requestId); + if (future != null) { + future.complete(accumulated); + } + } + } + private void handlePagedResponse(UUID requestId, InstalledModsResponse response) { List accumulated = this.paginatedAccumulator.computeIfAbsent(requestId, k -> new ArrayList<>()); diff --git a/docs/developers/modules.mdx b/docs/developers/modules.mdx index cdf6d7f8..a6d17d16 100644 --- a/docs/developers/modules.mdx +++ b/docs/developers/modules.mdx @@ -4,6 +4,8 @@ Apollo provides a wide-range of public modules that allow you to integrate direc These modules are available to all servers using Apollo and do not require any pre-approval. You are still expected to follow our [Acceptable Use](/apollo/acceptable-use) guidelines. +Some public modules also include [private features](/apollo/developers/private-modules) that require approval. These are noted on each module's page. + ### Available Modules 🔗 [Auto Text Hotkey](/apollo/developers/modules/autotexthotkey)
diff --git a/docs/developers/modules/inventory.mdx b/docs/developers/modules/inventory.mdx index fcd486eb..9d1ef296 100644 --- a/docs/developers/modules/inventory.mdx +++ b/docs/developers/modules/inventory.mdx @@ -1114,7 +1114,7 @@ The same layout built with raw payloads: [apollo-protos implementation](https:// ### Minigame Layout -A minigame overlay: map info, a live kill counter and mod-aware Show Map / Waypoints buttons using client actions, profile, settings and back to lobby buttons. +A minigame overlay: map info, a live kill counter and mod-aware Show Map / Waypoints buttons using client actions, profile, settings and back to lobby buttons. The mod aware buttons use the private [Mod Status API](/apollo/developers/private-modules/modstatus). ![Minigame Layout](/modules/inventory/minigame.png#center) @@ -1227,77 +1227,84 @@ public static void display(InventoryModule inventoryModule, Player viewer) { .onClick(ApolloButtonAction.runCommand("/settings")) .build(); - ModSettingModule modSettingModule = Apollo.getModuleManager().getModule(ModSettingModule.class); - boolean minimapEnabled = modSettingModule.getStatus(apolloPlayer, ModMinimap.ENABLED); - boolean waypointsEnabled = modSettingModule.getStatus(apolloPlayer, ModWaypoints.ENABLED); + List buttons = new ArrayList<>(Arrays.asList(mapInfo, kills, lobby, profile, settings)); + buttons.addAll(modButtons(apolloPlayer)); + inventoryModule.displayInventoryButtons(apolloPlayer, buttons); + }); +} - InventoryButton.InventoryButtonBuilder showMapBuilder = InventoryButton.builder() - .id("show-map") - .inventoryType(InventoryType.PLAYER) - .box(InventoryButtonBox.RIGHT) - .position(HudPosition.of(6, 52)) - .size(InventoryButton.SIZE_WIDE) - .shape(ApolloButtonShape.ROUNDED_SQUARE) - .content(ApolloButtonContent.builder() - .append(ItemStackIcon.builder() - .itemName("FILLED_MAP") - .build()) - .append(Component.text("Show Map")) - .scale(1.0F) - .build()); - - if (minimapEnabled) { - showMapBuilder - .backgroundColor(InventoryButton.DEFAULT_BACKGROUND_COLOR) - .borderColor(InventoryButton.DEFAULT_BORDER_COLOR) - .tooltip(ApolloButtonTooltip.of( - Component.text("Show Map", NamedTextColor.AQUA), - Component.text("Open the fullscreen minimap view", NamedTextColor.GRAY))) - .onClick(ApolloButtonAction.clientAction(ApolloButtonClientAction.OPEN_MINIMAP_VIEW)); - } else { - showMapBuilder - .backgroundColor(new Color(224, 64, 64, 128)) - .borderColor(new Color(255, 200, 200, 140)) - .tooltip(ApolloButtonTooltip.of(Component.text("Minimap mod must be enabled", NamedTextColor.RED))); - } +// Displaying these again with the same ids replaces the previous Show Map / Waypoints buttons +public static List modButtons(ApolloPlayer apolloPlayer) { + // getStatus is part of the private Mod Status API: https://lunarclient.dev/apollo/developers/private-modules/modstatus + ModSettingModule modSettingModule = Apollo.getModuleManager().getModule(ModSettingModule.class); + boolean minimapEnabled = modSettingModule.getStatus(apolloPlayer, ModMinimap.ENABLED); + boolean waypointsEnabled = modSettingModule.getStatus(apolloPlayer, ModWaypoints.ENABLED); + + InventoryButton.InventoryButtonBuilder showMapBuilder = InventoryButton.builder() + .id("show-map") + .inventoryType(InventoryType.PLAYER) + .box(InventoryButtonBox.RIGHT) + .position(HudPosition.of(6, 52)) + .size(InventoryButton.SIZE_WIDE) + .shape(ApolloButtonShape.ROUNDED_SQUARE) + .content(ApolloButtonContent.builder() + .append(ItemStackIcon.builder() + .itemName("FILLED_MAP") + .build()) + .append(Component.text("Show Map")) + .scale(1.0F) + .build()); - InventoryButton showMap = showMapBuilder.build(); + if (minimapEnabled) { + showMapBuilder + .backgroundColor(InventoryButton.DEFAULT_BACKGROUND_COLOR) + .borderColor(InventoryButton.DEFAULT_BORDER_COLOR) + .tooltip(ApolloButtonTooltip.of( + Component.text("Show Map", NamedTextColor.AQUA), + Component.text("Open the fullscreen minimap view", NamedTextColor.GRAY))) + .onClick(ApolloButtonAction.clientAction(ApolloButtonClientAction.OPEN_MINIMAP_VIEW)); + } else { + showMapBuilder + .backgroundColor(new Color(224, 64, 64, 128)) + .borderColor(new Color(255, 200, 200, 140)) + .tooltip(ApolloButtonTooltip.of(Component.text("Minimap mod must be enabled", NamedTextColor.RED))); + } - InventoryButton.InventoryButtonBuilder waypointsBuilder = InventoryButton.builder() - .id("waypoints") - .inventoryType(InventoryType.PLAYER) - .box(InventoryButtonBox.RIGHT) - .position(HudPosition.of(6, 84)) - .size(InventoryButton.SIZE_WIDE) - .shape(ApolloButtonShape.ROUNDED_SQUARE) - .content(ApolloButtonContent.builder() - .append(ItemStackIcon.builder() - .itemName("LODESTONE") - .build()) - .append(Component.text("Waypoints")) - .scale(1.0F) - .build()); - - if (waypointsEnabled) { - waypointsBuilder - .backgroundColor(InventoryButton.DEFAULT_BACKGROUND_COLOR) - .borderColor(InventoryButton.DEFAULT_BORDER_COLOR) - .tooltip(ApolloButtonTooltip.of( - Component.text("Waypoints", NamedTextColor.GOLD), - Component.text("Manage your waypoints", NamedTextColor.GRAY))) - .onClick(ApolloButtonAction.clientAction(ApolloButtonClientAction.OPEN_WAYPOINTS_MENU)); - } else { - waypointsBuilder - .backgroundColor(new Color(224, 64, 64, 128)) - .borderColor(new Color(255, 200, 200, 140)) - .tooltip(ApolloButtonTooltip.of(Component.text("Waypoints mod must be enabled", NamedTextColor.RED))); - } + InventoryButton showMap = showMapBuilder.build(); + + InventoryButton.InventoryButtonBuilder waypointsBuilder = InventoryButton.builder() + .id("waypoints") + .inventoryType(InventoryType.PLAYER) + .box(InventoryButtonBox.RIGHT) + .position(HudPosition.of(6, 84)) + .size(InventoryButton.SIZE_WIDE) + .shape(ApolloButtonShape.ROUNDED_SQUARE) + .content(ApolloButtonContent.builder() + .append(ItemStackIcon.builder() + .itemName("LODESTONE") + .build()) + .append(Component.text("Waypoints")) + .scale(1.0F) + .build()); - InventoryButton waypoints = waypointsBuilder.build(); + if (waypointsEnabled) { + waypointsBuilder + .backgroundColor(InventoryButton.DEFAULT_BACKGROUND_COLOR) + .borderColor(InventoryButton.DEFAULT_BORDER_COLOR) + .tooltip(ApolloButtonTooltip.of( + Component.text("Waypoints", NamedTextColor.GOLD), + Component.text("Manage your waypoints", NamedTextColor.GRAY))) + .onClick(ApolloButtonAction.clientAction(ApolloButtonClientAction.OPEN_WAYPOINTS_MENU)); + } else { + waypointsBuilder + .backgroundColor(new Color(224, 64, 64, 128)) + .borderColor(new Color(255, 200, 200, 140)) + .tooltip(ApolloButtonTooltip.of(Component.text("Waypoints mod must be enabled", NamedTextColor.RED))); + } - inventoryModule.displayInventoryButtons(apolloPlayer, Arrays.asList(mapInfo, kills, lobby, - profile, settings, showMap, waypoints)); - }); + InventoryButton waypoints = waypointsBuilder.build(); + + return Arrays.asList(showMap, waypoints); } private static int getKills(ApolloPlayer apolloViewer) { diff --git a/docs/developers/modules/modsetting.mdx b/docs/developers/modules/modsetting.mdx index 127b46e3..215ff90e 100644 --- a/docs/developers/modules/modsetting.mdx +++ b/docs/developers/modules/modsetting.mdx @@ -12,7 +12,7 @@ You can find all available mods and their options under the mods section. - Adds the ability to interact with Lunar Client mods. - Ability to enable/disable mods. - Ability to change, enable or disable mod settings within a mod. - - Ability to retrieve the current value of any mod and settings within a mod. + - Ability to retrieve the current value of any mod and settings within a mod ([private feature](/apollo/developers/private-modules/modstatus)). ![Mod Settings Module Example](/modules/modsettings/overview.png#center) @@ -22,65 +22,13 @@ You can find all available mods and their options under the mods section. ## Integration -### Setting Status API -The **Setting Status API** provides a simple way to retrieve the **current** value of any mod or any setting within a mod. +### Mod Status API +The **Mod Status API** allows you to **request** the current value of any mod option, and to listen for updates whenever one changes. -**Retrieve the current value for options** - -```java -private final ModSettingModule modSettingModule = Apollo.getModuleManager().getModule(ModSettingModule.class); - -private void printOptionStatusExample(Player player) { - Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(player.getUniqueId()); - apolloPlayerOpt.ifPresent(apolloPlayer -> { - // https://lunarclient.dev/apollo/developers/mods/waypoints#available-options - boolean waypointsEnabled = this.modSettingModule.getStatus(apolloPlayer, ModWaypoints.ENABLED); - - // https://lunarclient.dev/apollo/developers/mods/minimap#available-options - float minimapScale = this.modSettingModule.getStatus(apolloPlayer, ModMinimap.SCALE); - - // https://lunarclient.dev/apollo/developers/mods/fov#available-options - int fovDefaultFov = this.modSettingModule.getStatus(apolloPlayer, ModFov.DEFAULT_FOV); - - apolloPlayer.sendMessage(Component.text("Waypoints Enabled: ") - .append(Component.text(waypointsEnabled))); - - apolloPlayer.sendMessage(Component.text("Minimap Scale: ") - .append(Component.text(minimapScale))); - - apolloPlayer.sendMessage(Component.text("Fov Default Fov: ") - .append(Component.text(fovDefaultFov))); - }); -} -``` - -**Listening for Updates** - -Apollo fires the [ApolloUpdateModOptionEvent](/apollo/developers/events), whenever a Lunar Client Mod Option is updated. - -```java -import com.lunarclient.apollo.event.ApolloListener; -import com.lunarclient.apollo.event.EventBus; -import com.lunarclient.apollo.event.Listen; -import com.lunarclient.apollo.event.modsetting.ApolloUpdateModOptionEvent; -import java.util.Objects; -import net.kyori.adventure.text.Component; - -public class ApolloModStatusExample implements ApolloListener { - - public ApolloModStatusExample() { - EventBus.getBus().register(this); - } - - @Listen - private void onApolloUpdateModOption(ApolloUpdateModOptionEvent event) { - event.getPlayer().sendMessage(Component.text(event.getOption().getKey()) - .append(Component.text(" was updated to ")) - .append(Component.text(Objects.toString(event.getValue())))); - } - -} -``` + + The Mod Status API is a **private feature** of this module and not publicly available. The rest of the module, such as the Setting Interception API, stays public. + See [Mod Status](/apollo/developers/private-modules/modstatus) for usage, and [Private Modules](/apollo/developers/private-modules#how-to-request-access) to request access. + ### Setting Interception API The **Setting Interception API** allows you to **override** the value of any mod option. diff --git a/docs/developers/private-modules.mdx b/docs/developers/private-modules.mdx index bf57d20f..8fb7ca6a 100644 --- a/docs/developers/private-modules.mdx +++ b/docs/developers/private-modules.mdx @@ -1,18 +1,28 @@ # Private Modules -Apollo has private modules, that are access restricted extensions of the API. +Apollo has private modules and private features, which are access restricted parts of the API. -These modules are only available on pre-approved servers and will not work on servers that have not received approval. These private modules are still subject to our [Acceptable Use](/apollo/acceptable-use) guidelines. +- A **private module** is restricted as a whole, such as the Cosmetic module. +- A **private feature** is a restricted part of an otherwise public module, such as the Mod Status API of the Mod Setting module. The rest of that module stays public. + +In the Apollo API, private modules and features are marked with the `@RestrictedAccess` annotation. Access is granted separately for each private module and feature. + +These modules and features are only available on pre-approved servers and will not work on servers that have not received approval. They are still subject to our [Acceptable Use](/apollo/acceptable-use) guidelines. ### How to Request Access -We are not currently granting broad access to private modules. However, if you have a specific use-case in mind, you may request access by contacting **apollo@lunarclient.com**. +We are not currently granting broad access to private modules and features. However, if you have a specific use-case in mind, you may request access by contacting **apollo@lunarclient.com**. Please include: - Your server name & domain +- The private modules and features you need - A description of your use-case - Any relevant code snippets (if applicable) ### Available Modules 🔗 [Cosmetic](/apollo/developers/private-modules/cosmetic)
+ +### Available Features + +🔗 [Mod Status](/apollo/developers/private-modules/modstatus) (part of the [Mod Setting](/apollo/developers/modules/modsetting) module)
diff --git a/docs/developers/private-modules/_meta.json b/docs/developers/private-modules/_meta.json index 482e70cb..4c661c01 100644 --- a/docs/developers/private-modules/_meta.json +++ b/docs/developers/private-modules/_meta.json @@ -1,3 +1,4 @@ { - "cosmetic": "Cosmetic" + "cosmetic": "Cosmetic", + "modstatus": "Mod Status" } diff --git a/docs/developers/private-modules/modstatus.mdx b/docs/developers/private-modules/modstatus.mdx new file mode 100644 index 00000000..48f9fe89 --- /dev/null +++ b/docs/developers/private-modules/modstatus.mdx @@ -0,0 +1,181 @@ +import { Callout, Tab, Tabs } from 'nextra-theme-docs' + +# Mod Status + +## Overview + +The Mod Status API is part of the [Mod Setting](/apollo/developers/modules/modsetting) module and provides a simple way to retrieve the **current** value of any Lunar Client mod or setting within a mod for a player. + +- Request the player's current mod settings + - The response lists every mod option the player has changed from its default value, split into pages + - Read the value of any mod option afterwards, such as whether a mod is enabled or the minimap scale +- Listen for updates + - Get notified whenever the value of a player's mod option changes, including changes made by server overrides + + + The Mod Status API is a **private feature** of the public Mod Setting module and not publicly available. + To use this feature, you must be granted access by the Lunar Client team. [Learn More](/apollo/developers/private-modules) + + +## Integration + +### Sample Code + +Explore each integration by cycling through each tab, to find the best fit for your requirements and needs. + + + + + + +**Apollo API examples.** See [General](/apollo/developers/general) for common patterns and helpers. + + +**Request Mod Status** + +```java +public void requestModStatusExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + if (!apolloPlayerOpt.isPresent()) { + viewer.sendMessage("Join with Lunar Client to test this feature!"); + return; + } + + this.modSettingModule.requestModStatus(apolloPlayerOpt.get()) + .onSuccess(response -> { + List options = response.getElements() + .stream().map(status -> status.getOption().getKey() + "=" + status.getValue()) + .collect(Collectors.toList()); + + viewer.sendMessage("Found " + options.size() + " changed options: " + options); + }) + .onFailure(exception -> viewer.sendMessage("Failed to receive a response in time.")); +} +``` + +**Retrieve the current value for options** + +`getStatus` returns the values from the latest mod status response and any live updates since. + +```java +private final ModSettingModule modSettingModule = Apollo.getModuleManager().getModule(ModSettingModule.class); + +private void printOptionStatusExample(Player player) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(player.getUniqueId()); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.modSettingModule.requestModStatus(apolloPlayer) + .onSuccess(response -> { + // https://lunarclient.dev/apollo/developers/mods/waypoints#available-options + boolean waypointsEnabled = this.modSettingModule.getStatus(apolloPlayer, ModWaypoints.ENABLED); + + // https://lunarclient.dev/apollo/developers/mods/minimap#available-options + float minimapScale = this.modSettingModule.getStatus(apolloPlayer, ModMinimap.SCALE); + + // https://lunarclient.dev/apollo/developers/mods/fov#available-options + int fovDefaultFov = this.modSettingModule.getStatus(apolloPlayer, ModFov.DEFAULT_FOV); + + apolloPlayer.sendMessage(Component.text("Waypoints Enabled: ") + .append(Component.text(waypointsEnabled))); + + apolloPlayer.sendMessage(Component.text("Minimap Scale: ") + .append(Component.text(minimapScale))); + + apolloPlayer.sendMessage(Component.text("Fov Default Fov: ") + .append(Component.text(fovDefaultFov))); + }) + .onFailure(exception -> apolloPlayer.sendMessage(Component.text("Failed to receive a response in time.")))); +} +``` + +**Listening for Updates** + +Apollo fires the [ApolloUpdateModOptionEvent](/apollo/developers/events) whenever a Lunar Client mod option is updated. It is not fired for the options listed in a mod status response. + +```java +import com.lunarclient.apollo.event.ApolloListener; +import com.lunarclient.apollo.event.EventBus; +import com.lunarclient.apollo.event.Listen; +import com.lunarclient.apollo.event.modsetting.ApolloUpdateModOptionEvent; +import java.util.Objects; +import net.kyori.adventure.text.Component; + +public class ApolloModStatusExample implements ApolloListener { + + public ApolloModStatusExample() { + EventBus.getBus().register(this); + } + + @Listen + private void onApolloUpdateModOption(ApolloUpdateModOptionEvent event) { + event.getPlayer().sendMessage(Component.text(event.getOption().getKey()) + .append(Component.text(" was updated to ")) + .append(Component.text(Objects.toString(event.getValue())))); + } + +} +``` + + + + + + +**Lightweight Protobuf examples.** See [Lightweight Protobuf](/apollo/developers/lightweight/protobuf) for setup, and [Roundtrip Packets](/apollo/developers/lightweight/protobuf/roundtrip-packets) for `ApolloRoundtripProtoListener`. + + +**Request Mod Status** + +```java +public void requestModStatusExample(Player viewer) { + UUID requestId = UUID.randomUUID(); + + ModStatusRequest request = ModStatusRequest.newBuilder() + .setRequestId(ByteString.copyFromUtf8(requestId.toString())) + .build(); + + ApolloRoundtripProtoListener.getInstance().sendModStatusRequest(viewer, requestId, request) + .thenAccept(modOptions -> { + List keys = modOptions.stream() + .map(ModOptionStatus::getKey) + .collect(Collectors.toList()); + + viewer.sendMessage("Found " + keys.size() + " changed options: " + keys); + }).exceptionally(throwable -> { + viewer.sendMessage("Failed to receive a response in time."); + return null; + }); +} +``` + + + + + + +**Lightweight JSON examples.** See [Lightweight JSON](/apollo/developers/lightweight/json) for setup, and [Roundtrip Packets](/apollo/developers/lightweight/json/roundtrip-packets) for `ApolloRoundtripJsonListener`. + + +**Request Mod Status** + +```java +public void requestModStatusExample(Player viewer) { + UUID requestId = UUID.randomUUID(); + + ApolloRoundtripJsonListener.getInstance() + .sendPaginatedRequest(viewer, requestId, new JsonObject(), "lunarclient.apollo.modsetting.v1.ModStatusRequest") + .thenAccept(options -> { + List keys = options.stream() + .map(option -> option.get("key").getAsString()) + .collect(Collectors.toList()); + + viewer.sendMessage("Found " + keys.size() + " changed options: " + keys); + }).exceptionally(throwable -> { + viewer.sendMessage("Failed to receive a response in time."); + return null; + }); +} +``` + + + + diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/mods/ApolloModStatusExample.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/mods/ApolloModStatusExample.java index 71ef2a01..1a9a0f05 100644 --- a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/mods/ApolloModStatusExample.java +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/mods/ApolloModStatusExample.java @@ -73,25 +73,27 @@ private void onBlockPlace(BlockPlaceEvent event) { private void printOptionStatusExample(Player player) { Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(player.getUniqueId()); - apolloPlayerOpt.ifPresent(apolloPlayer -> { - // https://lunarclient.dev/apollo/developers/mods/waypoints#available-options - boolean waypointsEnabled = this.modSettingModule.getStatus(apolloPlayer, ModWaypoints.ENABLED); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.modSettingModule.requestModStatus(apolloPlayer) + .onSuccess(response -> { + // https://lunarclient.dev/apollo/developers/mods/waypoints#available-options + boolean waypointsEnabled = this.modSettingModule.getStatus(apolloPlayer, ModWaypoints.ENABLED); - // https://lunarclient.dev/apollo/developers/mods/minimap#available-options - float minimapScale = this.modSettingModule.getStatus(apolloPlayer, ModMinimap.SCALE); + // https://lunarclient.dev/apollo/developers/mods/minimap#available-options + float minimapScale = this.modSettingModule.getStatus(apolloPlayer, ModMinimap.SCALE); - // https://lunarclient.dev/apollo/developers/mods/fov#available-options - int fovDefaultFov = this.modSettingModule.getStatus(apolloPlayer, ModFov.DEFAULT_FOV); + // https://lunarclient.dev/apollo/developers/mods/fov#available-options + int fovDefaultFov = this.modSettingModule.getStatus(apolloPlayer, ModFov.DEFAULT_FOV); - apolloPlayer.sendMessage(Component.text("Waypoints Enabled: ") - .append(Component.text(waypointsEnabled))); + apolloPlayer.sendMessage(Component.text("Waypoints Enabled: ") + .append(Component.text(waypointsEnabled))); - apolloPlayer.sendMessage(Component.text("Minimap Scale: ") - .append(Component.text(minimapScale))); + apolloPlayer.sendMessage(Component.text("Minimap Scale: ") + .append(Component.text(minimapScale))); - apolloPlayer.sendMessage(Component.text("Fov Default Fov: ") - .append(Component.text(fovDefaultFov))); - }); + apolloPlayer.sendMessage(Component.text("Fov Default Fov: ") + .append(Component.text(fovDefaultFov))); + }) + .onFailure(exception -> apolloPlayer.sendMessage(Component.text("Failed to receive a response in time.")))); } } diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/mods/ModStatusCommand.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/mods/ModStatusCommand.java index 39bed666..91d1ea55 100644 --- a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/mods/ModStatusCommand.java +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/mods/ModStatusCommand.java @@ -25,10 +25,10 @@ import com.lunarclient.apollo.Apollo; import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.module.modsetting.ModOptionStatus; import com.lunarclient.apollo.module.modsetting.ModSettingModule; import com.lunarclient.apollo.option.Option; import com.lunarclient.apollo.player.ApolloPlayer; -import java.util.Map; import java.util.Optional; import org.bukkit.Bukkit; import org.bukkit.command.Command; @@ -86,20 +86,22 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command } private void sendCurrent(CommandSender sender, ApolloPlayer target) { - Map playerOptions = ApolloManager.getModsManager().getPlayerOptions().getPlayerOptions().get(target.getUniqueId()); - - sender.sendMessage("-------------------------------------"); - sender.sendMessage("Target: " + target.getName()); - sender.sendMessage(""); - - if (playerOptions != null && !playerOptions.isEmpty()) { - for (Map.Entry entry : playerOptions.entrySet()) { - sender.sendMessage(" - " + entry.getKey() + "=" + entry.getValue()); - } - } else { - sender.sendMessage("No options found!"); - } - - sender.sendMessage("-------------------------------------"); + this.modSettingModule.requestModStatus(target) + .onSuccess(response -> { + sender.sendMessage("-------------------------------------"); + sender.sendMessage("Target: " + target.getName()); + sender.sendMessage(""); + + if (!response.getElements().isEmpty()) { + for (ModOptionStatus status : response.getElements()) { + sender.sendMessage(" - " + status.getOption().getKey() + "=" + status.getValue()); + } + } else { + sender.sendMessage("No options found!"); + } + + sender.sendMessage("-------------------------------------"); + }) + .onFailure(exception -> sender.sendMessage("Failed to receive a response in time.")); } } diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/InventoryApiExample.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/InventoryApiExample.java index 016dd510..2e11b4d3 100644 --- a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/InventoryApiExample.java +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/InventoryApiExample.java @@ -39,6 +39,7 @@ import com.lunarclient.apollo.mods.impl.ModMinimap; import com.lunarclient.apollo.mods.impl.ModWaypoints; import com.lunarclient.apollo.module.inventory.InventoryModule; +import com.lunarclient.apollo.module.modsetting.ModSettingModule; import com.lunarclient.apollo.player.ApolloPlayer; import java.util.HashSet; import java.util.Optional; @@ -55,6 +56,7 @@ public class InventoryApiExample extends InventoryExample implements ApolloListener, Listener { private final InventoryModule inventoryModule = Apollo.getModuleManager().getModule(InventoryModule.class); + private final ModSettingModule modSettingModule = Apollo.getModuleManager().getModule(ModSettingModule.class); private final Set minigameViewers = new HashSet<>(); @@ -77,6 +79,11 @@ public void displayHubLayoutExample(Player viewer) { public void displayMinigameLayoutExample(Player viewer) { this.minigameViewers.add(viewer.getUniqueId()); MinigameLayout.display(this.inventoryModule, viewer); + + // Show Map / Waypoints follow the player's mod settings (private Mod Status API) + Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()).ifPresent(apolloPlayer -> this.modSettingModule + .requestModStatus(apolloPlayer) + .onSuccess(response -> this.inventoryModule.displayInventoryButtons(apolloPlayer, MinigameLayout.modButtons(apolloPlayer)))); } @Override @@ -120,6 +127,7 @@ private void onPlayerQuit(PlayerQuitEvent event) { } // Update Minigame layout if the player toggles their Minimap or Waypoint mod + // ApolloUpdateModOptionEvent is part of the private Mod Status API: https://lunarclient.dev/apollo/developers/private-modules/modstatus @Listen private void onApolloUpdateModOption(ApolloUpdateModOptionEvent event) { String optionKey = event.getOption().getKey(); @@ -127,15 +135,12 @@ private void onApolloUpdateModOption(ApolloUpdateModOptionEvent event) { return; } - UUID playerIdentifier = event.getPlayer().getUniqueId(); - if (!this.minigameViewers.contains(playerIdentifier)) { + ApolloPlayer apolloPlayer = event.getPlayer(); + if (!this.minigameViewers.contains(apolloPlayer.getUniqueId())) { return; } - Player viewer = Bukkit.getPlayer(playerIdentifier); - if (viewer != null) { - MinigameLayout.display(this.inventoryModule, viewer); - } + this.inventoryModule.displayInventoryButtons(apolloPlayer, MinigameLayout.modButtons(apolloPlayer)); } } diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/ModSettingsApiExample.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/ModSettingsApiExample.java index 76caec20..309e327f 100644 --- a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/ModSettingsApiExample.java +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/ModSettingsApiExample.java @@ -79,4 +79,24 @@ public void requestInstalledModsExample(Player viewer) { }); } + @Override + public void requestModStatusExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + if (!apolloPlayerOpt.isPresent()) { + viewer.sendMessage("Join with Lunar Client to test this feature!"); + return; + } + + this.modSettingModule.requestModStatus(apolloPlayerOpt.get()) + .onSuccess(response -> { + List options = response.getElements() + .stream().map(status -> status.getOption().getKey() + "=" + status.getValue()) + .collect(Collectors.toList()); + + viewer.sendMessage("Found " + options.size() + " changed options: " + options); + }) + .onFailure(exception -> viewer.sendMessage("Failed to receive a response in time.")); + } + } diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/inventorybuttons/MinigameLayout.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/inventorybuttons/MinigameLayout.java index dc1633db..231b6448 100644 --- a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/inventorybuttons/MinigameLayout.java +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/inventorybuttons/MinigameLayout.java @@ -42,7 +42,9 @@ import com.lunarclient.apollo.player.ApolloPlayer; import java.awt.Color; import java.time.Duration; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; import java.util.UUID; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -160,79 +162,86 @@ public static void display(InventoryModule inventoryModule, Player viewer) { .onClick(ApolloButtonAction.runCommand("/settings")) .build(); - ModSettingModule modSettingModule = Apollo.getModuleManager().getModule(ModSettingModule.class); - boolean minimapEnabled = modSettingModule.getStatus(apolloPlayer, ModMinimap.ENABLED); - boolean waypointsEnabled = modSettingModule.getStatus(apolloPlayer, ModWaypoints.ENABLED); - - InventoryButton.InventoryButtonBuilder showMapBuilder = InventoryButton.builder() - .id("show-map") - .inventoryType(InventoryType.PLAYER) - .box(InventoryButtonBox.RIGHT) - .position(HudPosition.of(6, 52)) - .size(InventoryButton.SIZE_WIDE) - .shape(ApolloButtonShape.ROUNDED_SQUARE) - .content(ApolloButtonContent.builder() - .append(ItemStackIcon.builder() - .itemName("FILLED_MAP") - .build()) - .append(Component.text("Show Map")) - .scale(1.0F) - .build()); - - if (minimapEnabled) { - showMapBuilder - .backgroundColor(InventoryButton.DEFAULT_BACKGROUND_COLOR) - .borderColor(InventoryButton.DEFAULT_BORDER_COLOR) - .tooltip(ApolloButtonTooltip.of( - Component.text("Show Map", NamedTextColor.AQUA), - Component.text("Open the fullscreen minimap view", NamedTextColor.GRAY))) - .onClick(ApolloButtonAction.clientAction(ApolloButtonClientAction.OPEN_MINIMAP_VIEW)); - } else { - showMapBuilder - .backgroundColor(new Color(224, 64, 64, 128)) - .borderColor(new Color(255, 200, 200, 140)) - .tooltip(ApolloButtonTooltip.of(Component.text("Minimap mod must be enabled", NamedTextColor.RED))); - } - - InventoryButton showMap = showMapBuilder.build(); - - InventoryButton.InventoryButtonBuilder waypointsBuilder = InventoryButton.builder() - .id("waypoints") - .inventoryType(InventoryType.PLAYER) - .box(InventoryButtonBox.RIGHT) - .position(HudPosition.of(6, 84)) - .size(InventoryButton.SIZE_WIDE) - .shape(ApolloButtonShape.ROUNDED_SQUARE) - .content(ApolloButtonContent.builder() - .append(ItemStackIcon.builder() - .itemName("LODESTONE") - .build()) - .append(Component.text("Waypoints")) - .scale(1.0F) - .build()); - - if (waypointsEnabled) { - waypointsBuilder - .backgroundColor(InventoryButton.DEFAULT_BACKGROUND_COLOR) - .borderColor(InventoryButton.DEFAULT_BORDER_COLOR) - .tooltip(ApolloButtonTooltip.of( - Component.text("Waypoints", NamedTextColor.GOLD), - Component.text("Manage your waypoints", NamedTextColor.GRAY))) - .onClick(ApolloButtonAction.clientAction(ApolloButtonClientAction.OPEN_WAYPOINTS_MENU)); - } else { - waypointsBuilder - .backgroundColor(new Color(224, 64, 64, 128)) - .borderColor(new Color(255, 200, 200, 140)) - .tooltip(ApolloButtonTooltip.of(Component.text("Waypoints mod must be enabled", NamedTextColor.RED))); - } - - InventoryButton waypoints = waypointsBuilder.build(); - - inventoryModule.displayInventoryButtons(apolloPlayer, Arrays.asList(mapInfo, kills, lobby, - profile, settings, showMap, waypoints)); + List buttons = new ArrayList<>(Arrays.asList(mapInfo, kills, lobby, profile, settings)); + buttons.addAll(modButtons(apolloPlayer)); + inventoryModule.displayInventoryButtons(apolloPlayer, buttons); }); } + // Displaying these again with the same ids replaces the previous Show Map / Waypoints buttons + public static List modButtons(ApolloPlayer apolloPlayer) { + // getStatus is part of the private Mod Status API: https://lunarclient.dev/apollo/developers/private-modules/modstatus + ModSettingModule modSettingModule = Apollo.getModuleManager().getModule(ModSettingModule.class); + boolean minimapEnabled = modSettingModule.getStatus(apolloPlayer, ModMinimap.ENABLED); + boolean waypointsEnabled = modSettingModule.getStatus(apolloPlayer, ModWaypoints.ENABLED); + + InventoryButton.InventoryButtonBuilder showMapBuilder = InventoryButton.builder() + .id("show-map") + .inventoryType(InventoryType.PLAYER) + .box(InventoryButtonBox.RIGHT) + .position(HudPosition.of(6, 52)) + .size(InventoryButton.SIZE_WIDE) + .shape(ApolloButtonShape.ROUNDED_SQUARE) + .content(ApolloButtonContent.builder() + .append(ItemStackIcon.builder() + .itemName("FILLED_MAP") + .build()) + .append(Component.text("Show Map")) + .scale(1.0F) + .build()); + + if (minimapEnabled) { + showMapBuilder + .backgroundColor(InventoryButton.DEFAULT_BACKGROUND_COLOR) + .borderColor(InventoryButton.DEFAULT_BORDER_COLOR) + .tooltip(ApolloButtonTooltip.of( + Component.text("Show Map", NamedTextColor.AQUA), + Component.text("Open the fullscreen minimap view", NamedTextColor.GRAY))) + .onClick(ApolloButtonAction.clientAction(ApolloButtonClientAction.OPEN_MINIMAP_VIEW)); + } else { + showMapBuilder + .backgroundColor(new Color(224, 64, 64, 128)) + .borderColor(new Color(255, 200, 200, 140)) + .tooltip(ApolloButtonTooltip.of(Component.text("Minimap mod must be enabled", NamedTextColor.RED))); + } + + InventoryButton showMap = showMapBuilder.build(); + + InventoryButton.InventoryButtonBuilder waypointsBuilder = InventoryButton.builder() + .id("waypoints") + .inventoryType(InventoryType.PLAYER) + .box(InventoryButtonBox.RIGHT) + .position(HudPosition.of(6, 84)) + .size(InventoryButton.SIZE_WIDE) + .shape(ApolloButtonShape.ROUNDED_SQUARE) + .content(ApolloButtonContent.builder() + .append(ItemStackIcon.builder() + .itemName("LODESTONE") + .build()) + .append(Component.text("Waypoints")) + .scale(1.0F) + .build()); + + if (waypointsEnabled) { + waypointsBuilder + .backgroundColor(InventoryButton.DEFAULT_BACKGROUND_COLOR) + .borderColor(InventoryButton.DEFAULT_BORDER_COLOR) + .tooltip(ApolloButtonTooltip.of( + Component.text("Waypoints", NamedTextColor.GOLD), + Component.text("Manage your waypoints", NamedTextColor.GRAY))) + .onClick(ApolloButtonAction.clientAction(ApolloButtonClientAction.OPEN_WAYPOINTS_MENU)); + } else { + waypointsBuilder + .backgroundColor(new Color(224, 64, 64, 128)) + .borderColor(new Color(255, 200, 200, 140)) + .tooltip(ApolloButtonTooltip.of(Component.text("Waypoints mod must be enabled", NamedTextColor.RED))); + } + + InventoryButton waypoints = waypointsBuilder.build(); + + return Arrays.asList(showMap, waypoints); + } + private static int getKills(ApolloPlayer apolloViewer) { Player player = Bukkit.getPlayer(apolloViewer.getUniqueId()); return player != null ? player.getStatistic(Statistic.PLAYER_KILLS) : 0; diff --git a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/ModSettingsCommand.java b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/ModSettingsCommand.java index b62551fa..104ce09e 100644 --- a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/ModSettingsCommand.java +++ b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/ModSettingsCommand.java @@ -44,7 +44,7 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command if (args.length != 1) { player.sendMessage("Usage: /modsettings "); - player.sendMessage("Usage: /modsettings "); + player.sendMessage("Usage: /modsettings "); return true; } @@ -75,9 +75,15 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command break; } + case "requestmodstatus": { + modSettingsExample.requestModStatusExample(player); + player.sendMessage("Requesting mod status....."); + break; + } + default: { player.sendMessage("Usage: /modsettings "); - player.sendMessage("Usage: /modsettings "); + player.sendMessage("Usage: /modsettings "); break; } } diff --git a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/ModSettingsExample.java b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/ModSettingsExample.java index 71777e2d..ae5b6d7d 100644 --- a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/ModSettingsExample.java +++ b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/ModSettingsExample.java @@ -36,4 +36,6 @@ public abstract class ModSettingsExample extends ApolloModuleExample { public abstract void requestInstalledModsExample(Player viewer); + public abstract void requestModStatusExample(Player viewer); + } diff --git a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/listener/ApolloRoundtripJsonListener.java b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/listener/ApolloRoundtripJsonListener.java index 1c2ff26f..518c3a0e 100644 --- a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/listener/ApolloRoundtripJsonListener.java +++ b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/listener/ApolloRoundtripJsonListener.java @@ -88,6 +88,9 @@ public void onPluginMessageReceived(@NonNull String channel, @NonNull Player pla } else if ("lunarclient.apollo.modsetting.v1.InstalledModsResponse".equals(type)) { UUID requestId = UUID.fromString(payload.get("request_id").getAsString().replace("+", "-")); this.parseModGroups(requestId, payload); + } else if ("lunarclient.apollo.modsetting.v1.ModStatusResponse".equals(type)) { + UUID requestId = UUID.fromString(payload.get("request_id").getAsString().replace("+", "-")); + this.parseModStatus(requestId, payload); } } @@ -155,6 +158,19 @@ private void parseModGroups(UUID requestId, JsonObject response) { this.handlePage(requestId, accumulated, response); } + private void parseModStatus(UUID requestId, JsonObject response) { + List accumulated = this.paginatedAccumulator.computeIfAbsent(requestId, k -> new ArrayList<>()); + + JsonArray modOptions = response.getAsJsonArray("mod_options"); + if (modOptions != null) { + for (JsonElement option : modOptions) { + accumulated.add(option.getAsJsonObject()); + } + } + + this.handlePage(requestId, accumulated, response); + } + private void handlePage(UUID requestId, List accumulated, JsonObject response) { int page = response.has("page") ? response.get("page").getAsInt() : 0; int totalPages = response.has("total_pages") ? response.get("total_pages").getAsInt() : 1; diff --git a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/ModSettingsJsonExample.java b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/ModSettingsJsonExample.java index d260febf..fc1fb4a8 100644 --- a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/ModSettingsJsonExample.java +++ b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/ModSettingsJsonExample.java @@ -83,4 +83,22 @@ public void requestInstalledModsExample(Player viewer) { }); } + @Override + public void requestModStatusExample(Player viewer) { + UUID requestId = UUID.randomUUID(); + + ApolloRoundtripJsonListener.getInstance() + .sendPaginatedRequest(viewer, requestId, new JsonObject(), "lunarclient.apollo.modsetting.v1.ModStatusRequest") + .thenAccept(options -> { + List keys = options.stream() + .map(option -> option.get("key").getAsString()) + .collect(Collectors.toList()); + + viewer.sendMessage("Found " + keys.size() + " changed options: " + keys); + }).exceptionally(throwable -> { + viewer.sendMessage("Failed to receive a response in time."); + return null; + }); + } + } diff --git a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/listener/ApolloRoundtripProtoListener.java b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/listener/ApolloRoundtripProtoListener.java index 03d43c72..903aa566 100644 --- a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/listener/ApolloRoundtripProtoListener.java +++ b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/listener/ApolloRoundtripProtoListener.java @@ -30,6 +30,9 @@ import com.lunarclient.apollo.example.proto.util.ProtobufPacketUtil; import com.lunarclient.apollo.modsetting.v1.InstalledModsResponse; import com.lunarclient.apollo.modsetting.v1.Mod; +import com.lunarclient.apollo.modsetting.v1.ModOptionStatus; +import com.lunarclient.apollo.modsetting.v1.ModStatusRequest; +import com.lunarclient.apollo.modsetting.v1.ModStatusResponse; import com.lunarclient.apollo.transfer.v1.PingResponse; import com.lunarclient.apollo.transfer.v1.TransferResponse; import java.util.ArrayList; @@ -56,6 +59,8 @@ public class ApolloRoundtripProtoListener implements PluginMessageListener { private final Map>> roundTripPacketFutures = new ConcurrentHashMap<>(); private final Map>> paginatedFutures = new ConcurrentHashMap<>(); private final Map> paginatedAccumulator = new ConcurrentHashMap<>(); + private final Map>> modStatusFutures = new ConcurrentHashMap<>(); + private final Map> modStatusAccumulator = new ConcurrentHashMap<>(); private final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(1); public ApolloRoundtripProtoListener(ApolloExamplePlugin plugin) { @@ -79,6 +84,10 @@ public void onPluginMessageReceived(@NonNull String channel, @NonNull Player pla InstalledModsResponse message = any.unpack(InstalledModsResponse.class); UUID requestId = UUID.fromString(message.getRequestId().toStringUtf8()); this.handlePagedResponse(requestId, message); + } else if (any.is(ModStatusResponse.class)) { + ModStatusResponse message = any.unpack(ModStatusResponse.class); + UUID requestId = UUID.fromString(message.getRequestId().toStringUtf8()); + this.handleModStatusPage(requestId, message); } } catch (InvalidProtocolBufferException e) { @@ -125,6 +134,38 @@ public CompletableFuture> sendPaginatedRequest(Player player, UUID req return future; } + public CompletableFuture> sendModStatusRequest(Player player, UUID requestId, ModStatusRequest request) { + ProtobufPacketUtil.sendPacket(player, request); + + CompletableFuture> future = new CompletableFuture<>(); + this.modStatusFutures.put(requestId, future); + + ScheduledFuture timeoutTask = this.executorService.schedule(() -> + future.completeExceptionally(new TimeoutException("Response timed out")), + 10, TimeUnit.SECONDS + ); + + future.whenComplete((result, throwable) -> { + timeoutTask.cancel(false); + this.modStatusAccumulator.remove(requestId); + }); + + return future; + } + + private void handleModStatusPage(UUID requestId, ModStatusResponse response) { + List accumulated = this.modStatusAccumulator.computeIfAbsent(requestId, k -> new ArrayList<>()); + accumulated.addAll(response.getModOptionsList()); + + if (response.getPage() == response.getTotalPages() - 1) { + this.modStatusAccumulator.remove(requestId); + CompletableFuture> future = this.modStatusFutures.remove(requestId); + if (future != null) { + future.complete(accumulated); + } + } + } + private void handlePagedResponse(UUID requestId, InstalledModsResponse response) { List accumulated = this.paginatedAccumulator.computeIfAbsent(requestId, k -> new ArrayList<>()); diff --git a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/ModSettingsProtoExample.java b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/ModSettingsProtoExample.java index 04780af3..94dc6798 100644 --- a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/ModSettingsProtoExample.java +++ b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/ModSettingsProtoExample.java @@ -32,6 +32,8 @@ import com.lunarclient.apollo.example.proto.util.ProtobufPacketUtil; import com.lunarclient.apollo.modsetting.v1.InstalledModsRequest; import com.lunarclient.apollo.modsetting.v1.Mod; +import com.lunarclient.apollo.modsetting.v1.ModOptionStatus; +import com.lunarclient.apollo.modsetting.v1.ModStatusRequest; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -90,4 +92,25 @@ public void requestInstalledModsExample(Player viewer) { }); } + @Override + public void requestModStatusExample(Player viewer) { + UUID requestId = UUID.randomUUID(); + + ModStatusRequest request = ModStatusRequest.newBuilder() + .setRequestId(ByteString.copyFromUtf8(requestId.toString())) + .build(); + + ApolloRoundtripProtoListener.getInstance().sendModStatusRequest(viewer, requestId, request) + .thenAccept(modOptions -> { + List keys = modOptions.stream() + .map(ModOptionStatus::getKey) + .collect(Collectors.toList()); + + viewer.sendMessage("Found " + keys.size() + " changed options: " + keys); + }).exceptionally(throwable -> { + viewer.sendMessage("Failed to receive a response in time."); + return null; + }); + } + } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index ba4c1777..4ed5c3ef 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ geantyref = "1.3.11" idea = "1.1.7" jetbrains = "24.0.1" lombok = "1.18.38" -protobuf = "0.2.5" +protobuf = "0.2.6" gson = "2.10.1" shadow = "9.4.1" spotless = "8.4.0" From fe907e4d4975d740ae8027967127aecf9f3eb84f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Bu=C4=8Dari=C4=87?= Date: Wed, 14 Oct 2026 21:47:28 +0200 Subject: [PATCH 4/6] Add more staff mods (#313) --- .../apollo/module/staffmod/StaffMod.java | 24 ++++++++++++++- docs/developers/lightweight/protobuf.mdx | 6 ++-- docs/developers/modules/staffmod.mdx | 29 +++++++++++++------ .../api/module/StaffModApiExample.java | 8 +++-- .../json/module/StaffModJsonExample.java | 8 ++--- .../proto/module/StaffModProtoExample.java | 6 ++-- gradle/libs.versions.toml | 2 +- 7 files changed, 59 insertions(+), 24 deletions(-) diff --git a/api/src/main/java/com/lunarclient/apollo/module/staffmod/StaffMod.java b/api/src/main/java/com/lunarclient/apollo/module/staffmod/StaffMod.java index 6585a5b2..14202213 100644 --- a/api/src/main/java/com/lunarclient/apollo/module/staffmod/StaffMod.java +++ b/api/src/main/java/com/lunarclient/apollo/module/staffmod/StaffMod.java @@ -26,10 +26,32 @@ /** * Represents a staff mod that can be enabled on the client. * + *

Enabling a staff mod may cause compatibility issues with anti-cheats.

+ * * @since 1.0.0 */ public enum StaffMod { - XRAY + /** + * Lets the player see through blocks. + * + * @since 1.0.0 + */ + XRAY, + + /** + * Automatically jumps while moving and keeps air speed up. + * + * @since 1.3.0 + */ + BHOP, + + /** + * Shows player nametags through walls and from far away, including + * sneaking, invisible and team-hidden players. + * + * @since 1.3.0 + */ + NAMETAGS } diff --git a/docs/developers/lightweight/protobuf.mdx b/docs/developers/lightweight/protobuf.mdx index 5845b980..5678478b 100644 --- a/docs/developers/lightweight/protobuf.mdx +++ b/docs/developers/lightweight/protobuf.mdx @@ -26,7 +26,7 @@ Available fields for each message, including their types, are available on the B com.lunarclient apollo-protos - 0.2.5 + 0.2.7 ``` @@ -41,7 +41,7 @@ Available fields for each message, including their types, are available on the B } dependencies { - api 'com.lunarclient:apollo-protos:0.2.5' + api 'com.lunarclient:apollo-protos:0.2.7' } ``` @@ -55,7 +55,7 @@ Available fields for each message, including their types, are available on the B } dependencies { - api("com.lunarclient:apollo-protos:0.2.5") + api("com.lunarclient:apollo-protos:0.2.7") } ``` diff --git a/docs/developers/modules/staffmod.mdx b/docs/developers/modules/staffmod.mdx index 8c547999..12d9a204 100644 --- a/docs/developers/modules/staffmod.mdx +++ b/docs/developers/modules/staffmod.mdx @@ -7,7 +7,7 @@ import { Callout, Tab, Tabs } from 'nextra-theme-docs' The staff mod module allows you to interact with Lunar Client's built in staff mods. - Ability to grant and remove staff mods found in Lunar Client for players. - - Ability to allow players to enable/disable the X-ray mod. + - Ability to allow players to enable/disable the X-ray, BHop and Nametags mods. ![Staff Mod Module Example](/modules/staffmod/overview.png#center) @@ -15,6 +15,10 @@ The staff mod module allows you to interact with Lunar Client's built in staff m Allow your staff to use hidden staff only mods, like xray! + + Enabling a staff mod may cause compatibility issues with anti-cheats. For example, your anti-cheat may flag staff members who use BHop, so exempt them from movement checks while it is granted. + + ## Integration ### Sample Code @@ -37,7 +41,8 @@ public void enableStaffModsExample(Player viewer) { } Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); - apolloPlayerOpt.ifPresent(apolloPlayer -> this.staffModModule.enableStaffMods(apolloPlayer, Collections.singletonList(StaffMod.XRAY), true)); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.staffModModule.enableStaffMods(apolloPlayer, + Arrays.asList(StaffMod.XRAY, StaffMod.BHOP, StaffMod.NAMETAGS), true)); } ``` @@ -46,7 +51,8 @@ public void enableStaffModsExample(Player viewer) { ```java public void disableStaffModsExample(Player viewer) { Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); - apolloPlayerOpt.ifPresent(apolloPlayer -> this.staffModModule.disableStaffMods(apolloPlayer, Collections.singletonList(StaffMod.XRAY))); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.staffModModule.disableStaffMods(apolloPlayer, + Arrays.asList(StaffMod.XRAY, StaffMod.BHOP, StaffMod.NAMETAGS))); } ``` @@ -62,6 +68,11 @@ public void disableStaffModsExample(Player viewer) { ## `StaffMod` Types * `XRAY` + - Lets players see through blocks. +* `BHOP` + - Automatically jumps while moving and keeps air speed up. +* `NAMETAGS` + - Shows player nametags through walls and from far away, including sneaking, invisible and team-hidden players. @@ -80,7 +91,7 @@ public void enableStaffModsExample(Player viewer) { } EnableStaffModsMessage message = EnableStaffModsMessage.newBuilder() - .addAllStaffMods(Collections.singletonList(StaffMod.STAFF_MOD_XRAY)) + .addAllStaffMods(Arrays.asList(StaffMod.STAFF_MOD_XRAY, StaffMod.STAFF_MOD_BHOP, StaffMod.STAFF_MOD_NAMETAGS)) .setEnabledByDefault(true) .build(); @@ -93,7 +104,7 @@ public void enableStaffModsExample(Player viewer) { ```java public void disableStaffModsExample(Player viewer) { DisableStaffModsMessage message = DisableStaffModsMessage.newBuilder() - .addAllStaffMods(Collections.singletonList(StaffMod.STAFF_MOD_XRAY)) + .addAllStaffMods(Arrays.asList(StaffMod.STAFF_MOD_XRAY, StaffMod.STAFF_MOD_BHOP, StaffMod.STAFF_MOD_NAMETAGS)) .build(); ProtobufPacketUtil.sendPacket(viewer, message); @@ -116,8 +127,8 @@ public void enableStaffModsExample(Player viewer) { return; } - // 1 = xray - JsonArray staffMods = Stream.of(1) + // 1 = xray, 2 = bhop, 3 = nametags + JsonArray staffMods = Stream.of(1, 2, 3) .map(JsonPrimitive::new) .collect(JsonArray::new, JsonArray::add, JsonArray::addAll); @@ -134,8 +145,8 @@ public void enableStaffModsExample(Player viewer) { ```java public void disableStaffModsExample(Player viewer) { - // 1 = xray - JsonArray staffMods = Stream.of(1) + // 1 = xray, 2 = bhop, 3 = nametags + JsonArray staffMods = Stream.of(1, 2, 3) .map(JsonPrimitive::new) .collect(JsonArray::new, JsonArray::add, JsonArray::addAll); diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/StaffModApiExample.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/StaffModApiExample.java index d38ae3da..6cee2b2b 100644 --- a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/StaffModApiExample.java +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/StaffModApiExample.java @@ -28,7 +28,7 @@ import com.lunarclient.apollo.module.staffmod.StaffMod; import com.lunarclient.apollo.module.staffmod.StaffModModule; import com.lunarclient.apollo.player.ApolloPlayer; -import java.util.Collections; +import java.util.Arrays; import java.util.Optional; import org.bukkit.entity.Player; @@ -43,13 +43,15 @@ public void enableStaffModsExample(Player viewer) { } Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); - apolloPlayerOpt.ifPresent(apolloPlayer -> this.staffModModule.enableStaffMods(apolloPlayer, Collections.singletonList(StaffMod.XRAY), true)); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.staffModModule.enableStaffMods(apolloPlayer, + Arrays.asList(StaffMod.XRAY, StaffMod.BHOP, StaffMod.NAMETAGS), true)); } @Override public void disableStaffModsExample(Player viewer) { Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); - apolloPlayerOpt.ifPresent(apolloPlayer -> this.staffModModule.disableStaffMods(apolloPlayer, Collections.singletonList(StaffMod.XRAY))); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.staffModModule.disableStaffMods(apolloPlayer, + Arrays.asList(StaffMod.XRAY, StaffMod.BHOP, StaffMod.NAMETAGS))); } } diff --git a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/StaffModJsonExample.java b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/StaffModJsonExample.java index ee0d0d87..058d07d4 100644 --- a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/StaffModJsonExample.java +++ b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/StaffModJsonExample.java @@ -39,8 +39,8 @@ public void enableStaffModsExample(Player viewer) { return; } - // 1 = xray - JsonArray staffMods = Stream.of(1) + // 1 = xray, 2 = bhop, 3 = nametags + JsonArray staffMods = Stream.of(1, 2, 3) .map(JsonPrimitive::new) .collect(JsonArray::new, JsonArray::add, JsonArray::addAll); @@ -54,8 +54,8 @@ public void enableStaffModsExample(Player viewer) { @Override public void disableStaffModsExample(Player viewer) { - // 1 = xray - JsonArray staffMods = Stream.of(1) + // 1 = xray, 2 = bhop, 3 = nametags + JsonArray staffMods = Stream.of(1, 2, 3) .map(JsonPrimitive::new) .collect(JsonArray::new, JsonArray::add, JsonArray::addAll); diff --git a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/StaffModProtoExample.java b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/StaffModProtoExample.java index 9af09b1a..1dc8e02b 100644 --- a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/StaffModProtoExample.java +++ b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/StaffModProtoExample.java @@ -28,7 +28,7 @@ import com.lunarclient.apollo.staffmod.v1.DisableStaffModsMessage; import com.lunarclient.apollo.staffmod.v1.EnableStaffModsMessage; import com.lunarclient.apollo.staffmod.v1.StaffMod; -import java.util.Collections; +import java.util.Arrays; import org.bukkit.entity.Player; public class StaffModProtoExample extends StaffModExample { @@ -40,7 +40,7 @@ public void enableStaffModsExample(Player viewer) { } EnableStaffModsMessage message = EnableStaffModsMessage.newBuilder() - .addAllStaffMods(Collections.singletonList(StaffMod.STAFF_MOD_XRAY)) + .addAllStaffMods(Arrays.asList(StaffMod.STAFF_MOD_XRAY, StaffMod.STAFF_MOD_BHOP, StaffMod.STAFF_MOD_NAMETAGS)) .setEnabledByDefault(true) .build(); @@ -50,7 +50,7 @@ public void enableStaffModsExample(Player viewer) { @Override public void disableStaffModsExample(Player viewer) { DisableStaffModsMessage message = DisableStaffModsMessage.newBuilder() - .addAllStaffMods(Collections.singletonList(StaffMod.STAFF_MOD_XRAY)) + .addAllStaffMods(Arrays.asList(StaffMod.STAFF_MOD_XRAY, StaffMod.STAFF_MOD_BHOP, StaffMod.STAFF_MOD_NAMETAGS)) .build(); ProtobufPacketUtil.sendPacket(viewer, message); diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 4ed5c3ef..b65deeaf 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -11,7 +11,7 @@ geantyref = "1.3.11" idea = "1.1.7" jetbrains = "24.0.1" lombok = "1.18.38" -protobuf = "0.2.6" +protobuf = "0.2.7" gson = "2.10.1" shadow = "9.4.1" spotless = "8.4.0" From afc86f76b8f33b4795930d15f859487a4a7b541c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Bu=C4=8Dari=C4=87?= Date: Wed, 14 Oct 2026 22:04:46 +0200 Subject: [PATCH 5/6] Sync LunarClient Mods & Options (#314) * Sync LunarClient Mods & Options * Update version tags to 1.3.0 --------- Co-authored-by: LunarClient Bot --- .../com/lunarclient/apollo/mods/Mods.java | 12 +- .../apollo/mods/impl/ModActionBar.java | 12 + .../apollo/mods/impl/ModArmorstatus.java | 132 +++++-- .../apollo/mods/impl/ModAttackIndicator.java | 38 +- .../apollo/mods/impl/ModAudioSubtitles.java | 12 + .../apollo/mods/impl/ModBossbar.java | 15 +- .../lunarclient/apollo/mods/impl/ModChat.java | 23 +- .../apollo/mods/impl/ModCoordinates.java | 12 + .../apollo/mods/impl/ModDamageTint.java | 2 + .../apollo/mods/impl/ModGuiScale.java | 7 +- .../apollo/mods/impl/ModHeightLimit.java | 214 ++++++++++ .../apollo/mods/impl/ModHypixelStats.java | 50 +++ .../apollo/mods/impl/ModInventoryMod.java | 11 + .../apollo/mods/impl/ModKnockbackTrainer.java | 2 + .../apollo/mods/impl/ModLocatorBar.java | 326 +++++++++++++++ .../apollo/mods/impl/ModMinimap.java | 12 + .../apollo/mods/impl/ModNickHider.java | 23 +- .../apollo/mods/impl/ModOverlayMod.java | 125 +++++- .../apollo/mods/impl/ModPackDisplay.java | 11 + .../apollo/mods/impl/ModPotionEffects.java | 171 ++++++-- .../apollo/mods/impl/ModSaturation.java | 35 +- .../apollo/mods/impl/ModScoreboard.java | 12 + .../apollo/mods/impl/ModSkyblock.java | 2 + .../apollo/mods/impl/ModTierTagger.java | 134 ++++--- .../apollo/mods/impl/ModTitles.java | 35 +- .../apollo/mods/impl/ModToggleSneak.java | 23 ++ .../apollo/mods/impl/ModViewAngles.java | 372 ++++++++++++++++++ docs/developers/mods/_meta.json | 4 + docs/developers/mods/actionbar.mdx | 7 + docs/developers/mods/armorstatus.mdx | 89 +++-- docs/developers/mods/attackindicator.mdx | 21 +- docs/developers/mods/audiosubtitles.mdx | 7 + docs/developers/mods/bossbar.mdx | 8 + docs/developers/mods/chat.mdx | 6 - docs/developers/mods/coordinates.mdx | 8 + docs/developers/mods/damagetint.mdx | 15 - docs/developers/mods/guiscale.mdx | 5 +- docs/developers/mods/heightlimit.mdx | 118 ++++++ docs/developers/mods/hypixelstats.mdx | 23 ++ docs/developers/mods/inventorymod.mdx | 6 + docs/developers/mods/knockbacktrainer.mdx | 14 - docs/developers/mods/locatorbar.mdx | 188 +++++++++ docs/developers/mods/minimap.mdx | 9 + docs/developers/mods/nickhider.mdx | 9 +- docs/developers/mods/overlaymod.mdx | 71 +++- docs/developers/mods/packdisplay.mdx | 6 + docs/developers/mods/potioneffects.mdx | 100 ++++- docs/developers/mods/saturation.mdx | 24 +- docs/developers/mods/scoreboard.mdx | 7 + docs/developers/mods/skyblock.mdx | 14 - docs/developers/mods/tiertagger.mdx | 34 +- docs/developers/mods/titles.mdx | 20 +- docs/developers/mods/togglesneak.mdx | 13 + docs/developers/mods/viewangles.mdx | 210 ++++++++++ 54 files changed, 2552 insertions(+), 307 deletions(-) create mode 100644 api/src/main/java/com/lunarclient/apollo/mods/impl/ModHeightLimit.java create mode 100644 api/src/main/java/com/lunarclient/apollo/mods/impl/ModHypixelStats.java create mode 100644 api/src/main/java/com/lunarclient/apollo/mods/impl/ModLocatorBar.java create mode 100644 api/src/main/java/com/lunarclient/apollo/mods/impl/ModViewAngles.java create mode 100644 docs/developers/mods/heightlimit.mdx create mode 100644 docs/developers/mods/hypixelstats.mdx create mode 100644 docs/developers/mods/locatorbar.mdx create mode 100644 docs/developers/mods/viewangles.mdx diff --git a/api/src/main/java/com/lunarclient/apollo/mods/Mods.java b/api/src/main/java/com/lunarclient/apollo/mods/Mods.java index 98e66355..808a4a4a 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/Mods.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/Mods.java @@ -52,12 +52,14 @@ import com.lunarclient.apollo.mods.impl.ModFreelook; import com.lunarclient.apollo.mods.impl.ModGlintColorizer; import com.lunarclient.apollo.mods.impl.ModGuiScale; +import com.lunarclient.apollo.mods.impl.ModHeightLimit; import com.lunarclient.apollo.mods.impl.ModHitColor; import com.lunarclient.apollo.mods.impl.ModHitbox; import com.lunarclient.apollo.mods.impl.ModHorseStats; import com.lunarclient.apollo.mods.impl.ModHurtCam; import com.lunarclient.apollo.mods.impl.ModHypixelBedwars; import com.lunarclient.apollo.mods.impl.ModHypixelMod; +import com.lunarclient.apollo.mods.impl.ModHypixelStats; import com.lunarclient.apollo.mods.impl.ModInventoryMod; import com.lunarclient.apollo.mods.impl.ModItemCounter; import com.lunarclient.apollo.mods.impl.ModItemCustomizer; @@ -68,6 +70,7 @@ import com.lunarclient.apollo.mods.impl.ModKnockbackTrainer; import com.lunarclient.apollo.mods.impl.ModLightOverlay; import com.lunarclient.apollo.mods.impl.ModLighting; +import com.lunarclient.apollo.mods.impl.ModLocatorBar; import com.lunarclient.apollo.mods.impl.ModMarkers; import com.lunarclient.apollo.mods.impl.ModMemory; import com.lunarclient.apollo.mods.impl.ModMenuBlur; @@ -116,6 +119,7 @@ import com.lunarclient.apollo.mods.impl.ModToggleSneak; import com.lunarclient.apollo.mods.impl.ModTotemCounter; import com.lunarclient.apollo.mods.impl.ModUhcOverlay; +import com.lunarclient.apollo.mods.impl.ModViewAngles; import com.lunarclient.apollo.mods.impl.ModWaila; import com.lunarclient.apollo.mods.impl.ModWaypoints; import com.lunarclient.apollo.mods.impl.ModWeatherChanger; @@ -141,10 +145,12 @@ public final class Mods { ModOneSevenVisuals.class, ModFps.class, ModCps.class, + ModViewAngles.class, ModToggleSneak.class, ModZoom.class, ModHypixelMod.class, ModHypixelBedwars.class, + ModHeightLimit.class, ModQuickplay.class, ModArmorstatus.class, ModKeystrokes.class, @@ -229,12 +235,14 @@ public final class Mods { ModKillSounds.class, ModInventoryMod.class, ModF3Display.class, + ModLocatorBar.class, ModGuiScale.class, ModKnockbackTrainer.class, + ModHypixelStats.class, ModRadio.class, ModUhcOverlay.class, - ModNeu.class, - ModSba.class + ModSba.class, + ModNeu.class ); private Mods() { diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModActionBar.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModActionBar.java index d416060f..866e3919 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModActionBar.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModActionBar.java @@ -57,6 +57,18 @@ public final class ModActionBar { .notifyClient() .build(); + /** + * Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + * + * @since 1.3.0 + */ + public static final SimpleOption LOCK_TO_VANILLA_POSITION = SimpleOption.builder() + .comment("Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on.") + .node("action-bar", "lock-to-vanilla-position").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + private ModActionBar() { } diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModArmorstatus.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModArmorstatus.java index 795eb6b9..ee93fb08 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModArmorstatus.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModArmorstatus.java @@ -51,20 +51,19 @@ public final class ModArmorstatus { * * @since 1.0.0 */ - public static final NumberOption SCALE = NumberOption.number() - .node("armorstatus", "scale").type(TypeToken.get(Float.class)) - .min(0.25F).max(5.0F) - .defaultValue(1.0F) + public static final SimpleOption MOVE_ARMOR_INDIVIDUALLY = SimpleOption.builder() + .node("armorstatus", "move-armor-individually").type(TypeToken.get(Boolean.class)) + .defaultValue(false) .notifyClient() .build(); /** * No documentation available. * - * @since 1.0.0 + * @since 1.3.0 */ - public static final SimpleOption MOVE_ARMOR_INDIVIDUALLY = SimpleOption.builder() - .node("armorstatus", "move-armor-individually").type(TypeToken.get(Boolean.class)) + public static final SimpleOption VANILLA_MODE = SimpleOption.builder() + .node("armorstatus", "vanilla-mode").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() .build(); @@ -72,14 +71,36 @@ public final class ModArmorstatus { /** * No documentation available. * - * @since 1.1.9 + * @since 1.3.0 */ - public static final SimpleOption HIDE_UNBREAKABLE_DURABILITY = SimpleOption.builder() - .node("armorstatus", "hide-unbreakable-durability").type(TypeToken.get(Boolean.class)) + public static final SimpleOption HOTBAR_ANCHOR = SimpleOption.builder() + .node("armorstatus", "hotbar-anchor").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption ROUNDED_CORNERS = SimpleOption.builder() + .node("armorstatus", "rounded-corners").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption HIDE_EMPTY_SLOTS = SimpleOption.builder() + .node("armorstatus", "hide-empty-slots").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * @@ -136,6 +157,17 @@ public final class ModArmorstatus { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.2.8 + */ + public static final SimpleOption BACKGROUND_COLOR = SimpleOption.builder() + .node("armorstatus", "background-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(0, 0, 0, 111)) + .notifyClient() + .build(); + /** * No documentation available. * @@ -159,14 +191,26 @@ public final class ModArmorstatus { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.2.8 + */ + public static final SimpleOption BORDER_COLOR = SimpleOption.builder() + .node("armorstatus", "border-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(0, 0, 0, 159)) + .notifyClient() + .build(); + /** * No documentation available. * * @since 1.0.0 */ - public static final SimpleOption DAMAGE_OVERLAY = SimpleOption.builder() - .node("armorstatus", "damage-overlay").type(TypeToken.get(Boolean.class)) - .defaultValue(true) + public static final NumberOption SCALE = NumberOption.number() + .node("armorstatus", "scale").type(TypeToken.get(Float.class)) + .min(0.25F).max(5.0F) + .defaultValue(1.0F) .notifyClient() .build(); @@ -175,8 +219,8 @@ public final class ModArmorstatus { * * @since 1.0.0 */ - public static final SimpleOption ITEM_DAMAGE = SimpleOption.builder() - .node("armorstatus", "item-damage").type(TypeToken.get(Boolean.class)) + public static final SimpleOption DAMAGE_OVERLAY = SimpleOption.builder() + .node("armorstatus", "damage-overlay").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); @@ -184,10 +228,10 @@ public final class ModArmorstatus { /** * No documentation available. * - * @since 1.0.0 + * @since 1.3.0 */ - public static final SimpleOption ARMOR_DAMAGE = SimpleOption.builder() - .node("armorstatus", "armor-damage").type(TypeToken.get(Boolean.class)) + public static final SimpleOption LOW_DURABILITY_INDICATOR = SimpleOption.builder() + .node("armorstatus", "low-durability-indicator").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); @@ -195,33 +239,34 @@ public final class ModArmorstatus { /** * No documentation available. * - * @since 1.0.0 + * @since 1.3.0 */ - public static final SimpleOption MAX_DAMAGE = SimpleOption.builder() - .node("armorstatus", "max-damage").type(TypeToken.get(Boolean.class)) - .defaultValue(false) + public static final NumberOption LOW_DURABILITY_THRESHOLD = NumberOption.number() + .node("armorstatus", "low-durability-threshold").type(TypeToken.get(Integer.class)) + .min(1).max(100) + .defaultValue(10) .notifyClient() .build(); /** * No documentation available. * - * @since 1.2.8 + * @since 1.0.0 */ - public static final SimpleOption BACKGROUND_COLOR = SimpleOption.builder() - .node("armorstatus", "background-color").type(TypeToken.get(Color.class)) - .defaultValue(new Color(0, 0, 0, 111)) + public static final SimpleOption ITEM_DAMAGE = SimpleOption.builder() + .node("armorstatus", "item-damage").type(TypeToken.get(Boolean.class)) + .defaultValue(true) .notifyClient() .build(); /** * No documentation available. * - * @since 1.2.8 + * @since 1.0.0 */ - public static final SimpleOption BORDER_COLOR = SimpleOption.builder() - .node("armorstatus", "border-color").type(TypeToken.get(Color.class)) - .defaultValue(new Color(0, 0, 0, 159)) + public static final SimpleOption ARMOR_DAMAGE = SimpleOption.builder() + .node("armorstatus", "armor-damage").type(TypeToken.get(Boolean.class)) + .defaultValue(true) .notifyClient() .build(); @@ -230,12 +275,24 @@ public final class ModArmorstatus { * * @since 1.0.0 */ - public static final SimpleOption STATIC_DAMAGE_COLORS = SimpleOption.builder() - .node("armorstatus", "static-damage-colors").type(TypeToken.get(Boolean.class)) + public static final SimpleOption MAX_DAMAGE = SimpleOption.builder() + .node("armorstatus", "max-damage").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() .build(); + /** + * Don't show damage value on items that are unbreakable. + * + * @since 1.1.9 + */ + public static final SimpleOption HIDE_UNBREAKABLE_DURABILITY = SimpleOption.builder() + .comment("Don't show damage value on items that are unbreakable") + .node("armorstatus", "hide-unbreakable-durability").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + /** * No documentation available. * @@ -313,6 +370,17 @@ public final class ModArmorstatus { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.0.0 + */ + public static final SimpleOption STATIC_DAMAGE_COLORS = SimpleOption.builder() + .node("armorstatus", "static-damage-colors").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + private ModArmorstatus() { } diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModAttackIndicator.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModAttackIndicator.java index 876e47f1..cae8fa07 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModAttackIndicator.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModAttackIndicator.java @@ -69,6 +69,18 @@ public final class ModAttackIndicator { .notifyClient() .build(); + /** + * Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + * + * @since 1.3.0 + */ + public static final SimpleOption LOCK_TO_VANILLA_POSITION = SimpleOption.builder() + .comment("Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on.") + .node("attack-indicator", "lock-to-vanilla-position").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * @@ -269,18 +281,6 @@ public final class ModAttackIndicator { .notifyClient() .build(); - /** - * Play a ding when the weapon cooldowns are done. - * - * @since 1.2.8 - */ - public static final SimpleOption ATTACK_INDICATOR_PLAY_SOUND_VANILLA = SimpleOption.builder() - .comment("Play a ding when the weapon cooldowns are done") - .node("attack-indicator", "attack-indicator-play-sound-vanilla").type(TypeToken.get(Boolean.class)) - .defaultValue(false) - .notifyClient() - .build(); - /** * No documentation available. * @@ -371,11 +371,25 @@ public final class ModAttackIndicator { .notifyClient() .build(); + /** + * Play a ding when the weapon cooldowns are done. + * + * @since 1.2.8 + */ + @Deprecated + public static final SimpleOption ATTACK_INDICATOR_PLAY_SOUND_VANILLA = SimpleOption.builder() + .comment("Play a ding when the weapon cooldowns are done") + .node("attack-indicator", "attack-indicator-play-sound-vanilla").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * Play a ding when the cooldowns/indicators are done (excluding Sleep Progress, Block Breaking, Consumables and Storage Items). * * @since 1.2.8 */ + @Deprecated public static final SimpleOption ATTACK_INDICATOR_PLAY_SOUND_CUSTOM = SimpleOption.builder() .comment("Play a ding when the cooldowns/indicators are done (excluding Sleep Progress, Block Breaking, Consumables and Storage Items)") .node("attack-indicator", "attack-indicator-play-sound-custom").type(TypeToken.get(Boolean.class)) diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModAudioSubtitles.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModAudioSubtitles.java index 1ab6249b..f51bd5a1 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModAudioSubtitles.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModAudioSubtitles.java @@ -126,6 +126,18 @@ public final class ModAudioSubtitles { .notifyClient() .build(); + /** + * Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + * + * @since 1.3.0 + */ + public static final SimpleOption LOCK_TO_VANILLA_POSITION = SimpleOption.builder() + .comment("Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on.") + .node("audio-subtitles", "lock-to-vanilla-position").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModBossbar.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModBossbar.java index 21d2461d..6a7f03b2 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModBossbar.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModBossbar.java @@ -103,11 +103,24 @@ public final class ModBossbar { .build(); /** - * No documentation available. + * Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + * + * @since 1.3.0 + */ + public static final SimpleOption LOCK_TO_VANILLA_POSITION = SimpleOption.builder() + .comment("Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on.") + .node("bossbar", "lock-to-vanilla-position").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale. * * @since 1.1.2 */ public static final SimpleOption USE_MINECRAFT_GUISCALE = SimpleOption.builder() + .comment("On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale.") .node("bossbar", "use-minecraft-g-u-i-scale").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModChat.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModChat.java index b428e8c2..42e08741 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModChat.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModChat.java @@ -184,17 +184,6 @@ public final class ModChat { .notifyClient() .build(); - /** - * No documentation available. - * - * @since 1.0.0 - */ - public static final SimpleOption CHAT_PING_SOUND = SimpleOption.builder() - .node("chat", "chat-ping-sound").type(TypeToken.get(Boolean.class)) - .defaultValue(true) - .notifyClient() - .build(); - /** * Requires the ping message to exactly contain your name.For example, if your name is Notch, this will ping on Notch but not Notch123. * @@ -536,6 +525,18 @@ public final class ModChat { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.0.0 + */ + @Deprecated + public static final SimpleOption CHAT_PING_SOUND = SimpleOption.builder() + .node("chat", "chat-ping-sound").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + private ModChat() { } diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModCoordinates.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModCoordinates.java index 66e1d91a..193996f9 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModCoordinates.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModCoordinates.java @@ -126,6 +126,18 @@ public final class ModCoordinates { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption DECIMAL_PLACES = NumberOption.number() + .node("coordinates", "decimal-places").type(TypeToken.get(Integer.class)) + .min(0).max(10) + .defaultValue(2) + .notifyClient() + .build(); + /** * No documentation available. * diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModDamageTint.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModDamageTint.java index 86d04e89..f1a64204 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModDamageTint.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModDamageTint.java @@ -88,6 +88,7 @@ public final class ModDamageTint { * * @since 1.0.0 */ + @Deprecated public static final SimpleOption HEARTBEAT_AUDIO = SimpleOption.builder() .comment("Plays a heartbeat, becoming faster the lower your health.") .node("damage-tint", "heartbeat-audio").type(TypeToken.get(Boolean.class)) @@ -100,6 +101,7 @@ public final class ModDamageTint { * * @since 1.2.2 */ + @Deprecated public static final NumberOption HEARTBEAT_AUDIO_VOLUME = NumberOption.number() .node("damage-tint", "heartbeat-audio-volume").type(TypeToken.get(Float.class)) .min(0.0F).max(1.0F) diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModGuiScale.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModGuiScale.java index e1974321..9ab6d649 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModGuiScale.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModGuiScale.java @@ -58,14 +58,15 @@ public final class ModGuiScale { .build(); /** - * No documentation available. + * 0 = Auto/Vanilla Handling. * * @since 1.2.8 */ public static final NumberOption INVENTORY_SCALE = NumberOption.number() + .comment("0 = Auto/Vanilla Handling") .node("gui-scale", "inventory-scale").type(TypeToken.get(Integer.class)) - .min(1).max(5) - .defaultValue(2) + .min(0).max(5) + .defaultValue(0) .notifyClient() .build(); diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModHeightLimit.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModHeightLimit.java new file mode 100644 index 00000000..ea1512b7 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModHeightLimit.java @@ -0,0 +1,214 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.mods.impl; + +import com.lunarclient.apollo.option.NumberOption; +import com.lunarclient.apollo.option.SimpleOption; +import io.leangen.geantyref.TypeToken; +import java.awt.Color; + +/** + * Block overlay and HUD display to help you build up to map height limits. + * + * @since 1.3.0 + */ +public final class ModHeightLimit { + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption ENABLED = SimpleOption.builder() + .node("height-limit", "enabled").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption SCALE = NumberOption.number() + .node("height-limit", "scale").type(TypeToken.get(Float.class)) + .min(0.25F).max(5.0F) + .defaultValue(1.0F) + .notifyClient() + .build(); + + /** + * How far around you the block overlay is drawn. + * + * @since 1.3.0 + */ + public static final NumberOption RENDER_RANGE = NumberOption.number() + .comment("How far around you the block overlay is drawn") + .node("height-limit", "render-range").type(TypeToken.get(Integer.class)) + .min(1).max(8) + .defaultValue(4) + .notifyClient() + .build(); + + /** + * Display height limit information on the HUD. + * + * @since 1.3.0 + */ + public static final SimpleOption HEIGHT_LIMIT_OVERLAY = SimpleOption.builder() + .comment("Display height limit information on the HUD") + .node("height-limit", "height-limit-overlay").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Adds a shadow to text. + * + * @since 1.3.0 + */ + public static final SimpleOption TEXT_SHADOW = SimpleOption.builder() + .comment("Adds a shadow to text") + .node("height-limit", "text-shadow").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BACKGROUND = SimpleOption.builder() + .node("height-limit", "background").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BORDER = SimpleOption.builder() + .node("height-limit", "border").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption BORDER_THICKNESS = NumberOption.number() + .node("height-limit", "border-thickness").type(TypeToken.get(Float.class)) + .min(0.5F).max(3.0F) + .defaultValue(0.5F) + .notifyClient() + .build(); + + /** + * Automatically determine text alignment from position. Disable to manually set alignment. + * + * @since 1.3.0 + */ + public static final SimpleOption AUTO_ALIGN = SimpleOption.builder() + .comment("Automatically determine text alignment from position. Disable to manually set alignment") + .node("height-limit", "auto-align").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Distance changes color depending on how close you are to the height limit. + * + * @since 1.3.0 + */ + public static final SimpleOption AUTO_COLOR_DISTANCE = SimpleOption.builder() + .comment("Distance changes color depending on how close you are to the height limit") + .node("height-limit", "auto-color-distance").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption TITLE_COLOR = SimpleOption.builder() + .node("height-limit", "title-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(255, 255, 85)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption TEXT_COLOR = SimpleOption.builder() + .node("height-limit", "text-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(255, 255, 255)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption NUMBER_COLOR = SimpleOption.builder() + .node("height-limit", "number-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(85, 255, 85)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BACKGROUND_COLOR = SimpleOption.builder() + .node("height-limit", "background-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(0, 0, 0, 111)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BORDER_COLOR = SimpleOption.builder() + .node("height-limit", "border-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(0, 0, 0, 159)) + .notifyClient() + .build(); + + private ModHeightLimit() { + } + +} diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModHypixelStats.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModHypixelStats.java new file mode 100644 index 00000000..b708187b --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModHypixelStats.java @@ -0,0 +1,50 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.mods.impl; + +import com.lunarclient.apollo.option.SimpleOption; +import io.leangen.geantyref.TypeToken; + +/** + * Tracks stats across different Hypixel games. + * + * @since 1.3.0 + */ +public final class ModHypixelStats { + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption ENABLED = SimpleOption.builder() + .node("hypixel-stats", "enabled").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + private ModHypixelStats() { + } + +} diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModInventoryMod.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModInventoryMod.java index b224de2e..4f38a74a 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModInventoryMod.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModInventoryMod.java @@ -69,6 +69,17 @@ public final class ModInventoryMod { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption CURSOR_RESET_CHEST_SCREENS_ONLY = SimpleOption.builder() + .node("inventory-mod", "cursor-reset-chest-screens-only").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + private ModInventoryMod() { } diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModKnockbackTrainer.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModKnockbackTrainer.java index 1a82c014..e88406dc 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModKnockbackTrainer.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModKnockbackTrainer.java @@ -74,6 +74,7 @@ public final class ModKnockbackTrainer { * * @since 1.2.9 */ + @Deprecated public static final SimpleOption FALLING_HIT_SOUND = SimpleOption.builder() .node("knockback-trainer", "falling-hit-sound").type(TypeToken.get(Boolean.class)) .defaultValue(true) @@ -85,6 +86,7 @@ public final class ModKnockbackTrainer { * * @since 1.2.9 */ + @Deprecated public static final NumberOption FALLING_HIT_SOUND_VOLUME = NumberOption.number() .node("knockback-trainer", "falling-hit-sound-volume").type(TypeToken.get(Float.class)) .min(0.0F).max(1.0F) diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModLocatorBar.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModLocatorBar.java new file mode 100644 index 00000000..e63357d5 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModLocatorBar.java @@ -0,0 +1,326 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.mods.impl; + +import com.lunarclient.apollo.option.NumberOption; +import com.lunarclient.apollo.option.SimpleOption; +import io.leangen.geantyref.TypeToken; + +/** + * Customize the locator bar's position, size, and displayed information. + * + * @since 1.3.0 + */ +public final class ModLocatorBar { + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption ENABLED = SimpleOption.builder() + .node("locator-bar", "enabled").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption HIDE_LOCATOR_BAR = SimpleOption.builder() + .node("locator-bar", "hide-locator-bar").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * Move and scale the locator bar like a HUD mod instead of keeping it in the hotbar. + * + * @since 1.3.0 + */ + public static final SimpleOption DETACHED = SimpleOption.builder() + .comment("Move and scale the locator bar like a HUD mod instead of keeping it in the hotbar") + .node("locator-bar", "detached").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption SCALE = NumberOption.number() + .node("locator-bar", "scale").type(TypeToken.get(Float.class)) + .min(0.5F).max(1.5F) + .defaultValue(1.0F) + .notifyClient() + .build(); + + /** + * Draw the head of a player instead of the colored dot. + * + * @since 1.3.0 + */ + public static final SimpleOption USE_PLAYER_HEADS = SimpleOption.builder() + .comment("Draw the head of a player instead of the colored dot") + .node("locator-bar", "use-player-heads").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption PLAYER_HEAD_SCALE = NumberOption.number() + .node("locator-bar", "player-head-scale").type(TypeToken.get(Float.class)) + .min(0.5F).max(2.0F) + .defaultValue(1.0F) + .notifyClient() + .build(); + + /** + * Draw an outline around the head with the dot color. + * + * @since 1.3.0 + */ + public static final SimpleOption PLAYER_HEAD_HIGHLIGHT = SimpleOption.builder() + .comment("Draw an outline around the head with the dot color") + .node("locator-bar", "player-head-highlight").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Players beyond the range show as the colored dot. + * + * @since 1.3.0 + */ + public static final SimpleOption LIMIT_HEAD_RANGE = SimpleOption.builder() + .comment("Players beyond the range show as the colored dot") + .node("locator-bar", "limit-head-range").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * The maximum distance in blocks at which player heads show. + * + * @since 1.3.0 + */ + public static final NumberOption PLAYER_HEAD_DISPLAY_RANGE = NumberOption.number() + .comment("The maximum distance in blocks at which player heads show") + .node("locator-bar", "player-head-display-range").type(TypeToken.get(Integer.class)) + .min(16).max(332) + .defaultValue(100) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_PLAYER_NAME = SimpleOption.builder() + .node("locator-bar", "show-player-name").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption PLAYER_NAME_SCALE = NumberOption.number() + .node("locator-bar", "player-name-scale").type(TypeToken.get(Float.class)) + .min(0.5F).max(1.0F) + .defaultValue(1.0F) + .notifyClient() + .build(); + + /** + * Only draw the name of a player when you look toward them. + * + * @since 1.3.0 + */ + public static final SimpleOption ONLY_SHOW_NAME_WHEN_LOOKING_NEAR = SimpleOption.builder() + .comment("Only draw the name of a player when you look toward them") + .node("locator-bar", "only-show-name-when-looking-near").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * Only draw the names of players within the range. + * + * @since 1.3.0 + */ + public static final SimpleOption LIMIT_NAME_RANGE = SimpleOption.builder() + .comment("Only draw the names of players within the range") + .node("locator-bar", "limit-name-range").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * The maximum distance in blocks at which player names show. + * + * @since 1.3.0 + */ + public static final NumberOption PLAYER_NAME_DISPLAY_RANGE = NumberOption.number() + .comment("The maximum distance in blocks at which player names show") + .node("locator-bar", "player-name-display-range").type(TypeToken.get(Integer.class)) + .min(16).max(332) + .defaultValue(100) + .notifyClient() + .build(); + + /** + * Color the player name with their team color, or with their dot color when they have no team. + * + * @since 1.3.0 + */ + public static final SimpleOption COLORED_PLAYER_NAME = SimpleOption.builder() + .comment("Color the player name with their team color, or with their dot color when they have no team") + .node("locator-bar", "colored-player-name").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * When names overlap, only draw the name closest to the middle of the bar. + * + * @since 1.3.0 + */ + public static final SimpleOption HIDE_OVERLAPPING_NAMES = SimpleOption.builder() + .comment("When names overlap, only draw the name closest to the middle of the bar") + .node("locator-bar", "hide-overlapping-names").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Cut names longer than 8 characters, but keep them different from other players. + * + * @since 1.3.0 + */ + public static final SimpleOption CUT_LONG_NAMES = SimpleOption.builder() + .comment("Cut names longer than 8 characters, but keep them different from other players") + .node("locator-bar", "cut-long-names").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_DIRECTION = SimpleOption.builder() + .node("locator-bar", "show-direction").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * Show +Z, -Z, +X and -X instead of the direction letters. + * + * @since 1.3.0 + */ + public static final SimpleOption USE_COORDINATE_DIRECTIONS = SimpleOption.builder() + .comment("Show +Z, -Z, +X and -X instead of the direction letters") + .node("locator-bar", "use-coordinate-directions").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * Draw the dots or player heads. Turn this off to only show the names. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_BAR_ICONS = SimpleOption.builder() + .comment("Draw the dots or player heads. Turn this off to only show the names") + .node("locator-bar", "show-bar-icons").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Draw the waypoints on the xp bar instead of the locator bar. + * + * @since 1.3.0 + */ + public static final SimpleOption USE_XP_BAR = SimpleOption.builder() + .comment("Draw the waypoints on the xp bar instead of the locator bar") + .node("locator-bar", "use-xp-bar").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * Adds a shadow to text. + * + * @since 1.3.0 + */ + public static final SimpleOption TEXT_SHADOW = SimpleOption.builder() + .comment("Adds a shadow to text") + .node("locator-bar", "text-shadow").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Only show the extra info while the peek keybind is held down. + * + * @since 1.3.0 + */ + public static final SimpleOption LOCATOR_BAR_PEEK = SimpleOption.builder() + .comment("Only show the extra info while the peek keybind is held down") + .node("locator-bar", "locator-bar-peek").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * Hide the locator bar until you hold the peek keybind. + * + * @since 1.3.0 + */ + public static final SimpleOption ONLY_SHOW_WHILE_PEEKING = SimpleOption.builder() + .comment("Hide the locator bar until you hold the peek keybind") + .node("locator-bar", "only-show-while-peeking").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + private ModLocatorBar() { + } + +} diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModMinimap.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModMinimap.java index b4a0429f..cc436b39 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModMinimap.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModMinimap.java @@ -58,6 +58,18 @@ public final class ModMinimap { .notifyClient() .build(); + /** + * Create a viewable image file on your pc of the discovered map areas.For singleplayer, it's saved in the world folderFor Multiplayer, it's saved in the .minecraft folder. + * + * @since 1.3.0 + */ + public static final SimpleOption MINIMAP_SAVE_AS_PICTURE_FILE = SimpleOption.builder() + .comment("Create a viewable image file on your pc of the discovered map areas.For singleplayer, it's saved in the world folderFor Multiplayer, it's saved in the .minecraft folder") + .node("minimap", "minimap-save-as-picture-file").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModNickHider.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModNickHider.java index bcc3874a..46bc470e 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModNickHider.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModNickHider.java @@ -45,44 +45,48 @@ public final class ModNickHider { .build(); /** - * No documentation available. + * Replaces your Hypixel nick with your real name, or with your Nickname when Hide Your Real Name is on. * * @since 1.0.0 */ public static final SimpleOption HIDE_NAME = SimpleOption.builder() + .comment("Replaces your Hypixel nick with your real name, or with your Nickname when Hide Your Real Name is on") .node("nick-hider", "hide-name").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); /** - * No documentation available. + * Replaces your real name with your Nickname. * * @since 1.0.0 */ public static final SimpleOption HIDE_REAL_NAME = SimpleOption.builder() + .comment("Replaces your real name with your Nickname") .node("nick-hider", "hide-real-name").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); /** - * No documentation available. + * Replaces the names of other players with the Hidden Player Prefix and a number. * * @since 1.0.0 */ public static final SimpleOption HIDE_OTHERS_NAMES = SimpleOption.builder() + .comment("Replaces the names of other players with the Hidden Player Prefix and a number") .node("nick-hider", "hide-others-names").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() .build(); /** - * No documentation available. + * Shows every hidden player as the prefix followed by the Hidden Player Suffix, instead of numbering them. * * @since 1.2.2 */ public static final SimpleOption CUSTOM_SUFFIX = SimpleOption.builder() + .comment("Shows every hidden player as the prefix followed by the Hidden Player Suffix, instead of numbering them") .node("nick-hider", "custom-suffix").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() @@ -100,33 +104,36 @@ public final class ModNickHider { .build(); /** - * No documentation available. + * Shows you as Steve or Alex, or with a set skin from another player. * * @since 1.0.0 */ public static final SimpleOption HIDE_OWN_SKIN = SimpleOption.builder() + .comment("Shows you as Steve or Alex, or with a set skin from another player") .node("nick-hider", "hide-own-skin").type(TypeToken.get(Boolean.class)) - .defaultValue(true) + .defaultValue(false) .notifyClient() .build(); /** - * No documentation available. + * Shows your own skin even when a server changes it, for example with a Hypixel nick. * * @since 1.0.0 */ public static final SimpleOption USE_REAL_SKIN = SimpleOption.builder() + .comment("Shows your own skin even when a server changes it, for example with a Hypixel nick") .node("nick-hider", "use-real-skin").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); /** - * No documentation available. + * Shows other players as Steve or Alex. * * @since 1.0.0 */ public static final SimpleOption HIDE_OTHERS_SKIN = SimpleOption.builder() + .comment("Shows other players as Steve or Alex") .node("nick-hider", "hide-others-skin").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModOverlayMod.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModOverlayMod.java index b04034dd..0c81ad5e 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModOverlayMod.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModOverlayMod.java @@ -58,6 +58,18 @@ public final class ModOverlayMod { .notifyClient() .build(); + /** + * Stop your hand from bobbing while holding a map. + * + * @since 1.3.0 + */ + public static final SimpleOption NO_MAP_BOBBING = SimpleOption.builder() + .comment("Stop your hand from bobbing while holding a map.") + .node("overlay-mod", "no-map-bobbing").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * @@ -130,6 +142,18 @@ public final class ModOverlayMod { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption FISHING_BOBBER_OVERLAY = NumberOption.number() + .node("overlay-mod", "fishing-bobber-overlay").type(TypeToken.get(Float.class)) + .min(0.0F).max(1.0F) + .defaultValue(1.0F) + .notifyClient() + .build(); + /** * Hides grass and double grass blocks. * @@ -480,7 +504,18 @@ public final class ModOverlayMod { */ public static final SimpleOption XP_ORB_COLOR = SimpleOption.builder() .node("overlay-mod", "xp-orb-color").type(TypeToken.get(Color.class)) - .defaultValue(new Color(255, 255, 255, 128)) + .defaultValue(new Color(128, 255, 32, 128)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption XP_HOTBAR_TEXT_COLOR = SimpleOption.builder() + .node("overlay-mod", "xp-hotbar-text-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(128, 255, 32)) .notifyClient() .build(); @@ -518,6 +553,72 @@ public final class ModOverlayMod { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption CUSTOM_GUI_COLORS = SimpleOption.builder() + .node("overlay-mod", "custom-gui-colors").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption CONTAINER_TINT = SimpleOption.builder() + .node("overlay-mod", "container-tint").type(TypeToken.get(Color.class)) + .defaultValue(new Color(75, 75, 75)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption HOTBAR_TINT = SimpleOption.builder() + .node("overlay-mod", "hotbar-tint").type(TypeToken.get(Color.class)) + .defaultValue(new Color(75, 75, 75)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption MENU_TINT = SimpleOption.builder() + .node("overlay-mod", "menu-tint").type(TypeToken.get(Color.class)) + .defaultValue(new Color(75, 75, 75)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption GUI_TEXT_COLOR = SimpleOption.builder() + .node("overlay-mod", "gui-text-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(215, 215, 215)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption MENU_TEXT_COLOR = SimpleOption.builder() + .node("overlay-mod", "menu-text-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(215, 215, 215)) + .notifyClient() + .build(); + /** * Improve visibility when riding a horse. * @@ -530,6 +631,28 @@ public final class ModOverlayMod { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption HEADLESS_LLAMAS = SimpleOption.builder() + .node("overlay-mod", "headless-l-lamas").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption HEADLESS_CAMELS = SimpleOption.builder() + .node("overlay-mod", "headless-camels").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModPackDisplay.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModPackDisplay.java index be91fbc3..3cef003d 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModPackDisplay.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModPackDisplay.java @@ -102,6 +102,17 @@ public final class ModPackDisplay { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption IGNORE_SERVER_PACK = SimpleOption.builder() + .node("pack-display", "ignore-server-pack").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * Adds a shadow to text. * diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModPotionEffects.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModPotionEffects.java index 649d2ee1..5a5bd241 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModPotionEffects.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModPotionEffects.java @@ -92,6 +92,18 @@ public final class ModPotionEffects { .notifyClient() .build(); + /** + * Use the vanilla spacing between each effect tile. + * + * @since 1.3.0 + */ + public static final SimpleOption VANILLA_SPACING = SimpleOption.builder() + .comment("Use the vanilla spacing between each effect tile") + .node("potion-effects", "vanilla-spacing").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * @@ -151,11 +163,33 @@ public final class ModPotionEffects { /** * No documentation available. * - * @since 1.0.0 + * @since 1.1.9 */ - public static final SimpleOption SHOW_IN_INVENTORY = SimpleOption.builder() - .node("potion-effects", "show-in-inventory").type(TypeToken.get(Boolean.class)) - .defaultValue(true) + public static final SimpleOption FORMATTED_DURATIONS = SimpleOption.builder() + .node("potion-effects", "formatted-durations").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.1.9 + */ + public static final SimpleOption UPPERCASE_POTION_NAMES = SimpleOption.builder() + .node("potion-effects", "uppercase-potion-names").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.1.9 + */ + public static final SimpleOption REVERSED_TEXT = SimpleOption.builder() + .node("potion-effects", "reversed-text").type(TypeToken.get(Boolean.class)) + .defaultValue(false) .notifyClient() .build(); @@ -219,21 +253,45 @@ public final class ModPotionEffects { /** * No documentation available. * - * @since 1.1.9 + * @since 1.0.0 */ - public static final SimpleOption UPPERCASE_POTION_NAMES = SimpleOption.builder() - .node("potion-effects", "uppercase-potion-names").type(TypeToken.get(Boolean.class)) - .defaultValue(false) + public static final SimpleOption SHOW_IN_INVENTORY = SimpleOption.builder() + .node("potion-effects", "show-in-inventory").type(TypeToken.get(Boolean.class)) + .defaultValue(true) .notifyClient() .build(); /** * No documentation available. * - * @since 1.1.9 + * @since 1.0.0 */ - public static final SimpleOption REVERSED_TEXT = SimpleOption.builder() - .node("potion-effects", "reversed-text").type(TypeToken.get(Boolean.class)) + public static final SimpleOption HIDE_MODERN_ICONS = SimpleOption.builder() + .node("potion-effects", "hide-modern-icons").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Completely hide the potion effects mod HUD. + * + * @since 1.2.9 + */ + public static final SimpleOption HIDE_POTION_STATUS = SimpleOption.builder() + .comment("Completely hide the potion effects mod HUD") + .node("potion-effects", "hide-potion-status").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * Show effect duration with a progress bar in the inventory/hud. + * + * @since 1.3.0 + */ + public static final SimpleOption EFFECT_BARS = SimpleOption.builder() + .comment("Show effect duration with a progress bar in the inventory/hud") + .node("potion-effects", "effect-bars").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() .build(); @@ -241,10 +299,33 @@ public final class ModPotionEffects { /** * No documentation available. * - * @since 1.1.9 + * @since 1.3.0 */ - public static final SimpleOption FORMATTED_DURATIONS = SimpleOption.builder() - .node("potion-effects", "formatted-durations").type(TypeToken.get(Boolean.class)) + public static final SimpleOption EFFECT_BAR_VANILLA_HUD = SimpleOption.builder() + .node("potion-effects", "effect-bar-vanilla-hud").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption EFFECT_BAR_INVENTORY = SimpleOption.builder() + .node("potion-effects", "effect-bar-inventory").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Show the duration bars on Lunar potion effect status huds. + * + * @since 1.3.0 + */ + public static final SimpleOption EFFECT_BAR_LUNAR_HUD = SimpleOption.builder() + .comment("Show the duration bars on Lunar potion effect status huds") + .node("potion-effects", "effect-bar-lunar-hud").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() .build(); @@ -252,26 +333,48 @@ public final class ModPotionEffects { /** * No documentation available. * - * @since 1.0.0 + * @since 1.3.0 */ - public static final SimpleOption HIDE_MODERN_ICONS = SimpleOption.builder() - .node("potion-effects", "hide-modern-icons").type(TypeToken.get(Boolean.class)) + public static final SimpleOption EFFECT_BAR_HIDE_AMBIENT = SimpleOption.builder() + .node("potion-effects", "effect-bar-hide-ambient").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); /** - * Completely hide the potion effects mod HUD. + * Do a gradient animation on the bar color. * - * @since 1.2.9 + * @since 1.3.0 */ - public static final SimpleOption HIDE_POTION_STATUS = SimpleOption.builder() - .comment("Completely hide the potion effects mod HUD") - .node("potion-effects", "hide-potion-status").type(TypeToken.get(Boolean.class)) + public static final SimpleOption EFFECT_BAR_GRADIENT = SimpleOption.builder() + .comment("Do a gradient animation on the bar color") + .node("potion-effects", "effect-bar-gradient").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption EFFECT_BAR_CUSTOM_COLOR = SimpleOption.builder() + .node("potion-effects", "effect-bar-custom-color").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption EFFECT_BAR_COLOR = SimpleOption.builder() + .node("potion-effects", "effect-bar-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(255, 255, 255)) + .notifyClient() + .build(); + /** * No documentation available. * @@ -431,6 +534,30 @@ public final class ModPotionEffects { .notifyClient() .build(); + /** + * Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + * + * @since 1.3.0 + */ + public static final SimpleOption LOCK_TO_VANILLA_POSITION = SimpleOption.builder() + .comment("Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on.") + .node("potion-effects", "lock-to-vanilla-position").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale. + * + * @since 1.3.0 + */ + public static final SimpleOption USE_MINECRAFT_GUISCALE = SimpleOption.builder() + .comment("On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale.") + .node("potion-effects", "use-minecraft-g-u-i-scale").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModSaturation.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModSaturation.java index bae9e1b2..ddd2d879 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModSaturation.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModSaturation.java @@ -25,6 +25,7 @@ import com.lunarclient.apollo.option.SimpleOption; import io.leangen.geantyref.TypeToken; +import java.awt.Color; /** * Saturation HUD with AppleSkin features. @@ -60,8 +61,8 @@ public final class ModSaturation { * * @since 1.0.0 */ - public static final SimpleOption SHOW_APPLESKIN_TOOLTIP = SimpleOption.builder() - .node("saturation", "show-appleskin-tooltip").type(TypeToken.get(Boolean.class)) + public static final SimpleOption SHOW_HELD_ITEM_HUNGER = SimpleOption.builder() + .node("saturation", "show-held-item-hunger").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); @@ -71,8 +72,8 @@ public final class ModSaturation { * * @since 1.0.0 */ - public static final SimpleOption SHOW_HELD_ITEM_HUNGER = SimpleOption.builder() - .node("saturation", "show-held-item-hunger").type(TypeToken.get(Boolean.class)) + public static final SimpleOption SHOW_HELD_ITEM_SATURATION = SimpleOption.builder() + .node("saturation", "show-held-item-saturation").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); @@ -82,12 +83,34 @@ public final class ModSaturation { * * @since 1.0.0 */ - public static final SimpleOption SHOW_HELD_ITEM_SATURATION = SimpleOption.builder() - .node("saturation", "show-held-item-saturation").type(TypeToken.get(Boolean.class)) + public static final SimpleOption SHOW_APPLESKIN_TOOLTIP = SimpleOption.builder() + .node("saturation", "show-appleskin-tooltip").type(TypeToken.get(Boolean.class)) .defaultValue(true) .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption USE_INVERSE_COLOR = SimpleOption.builder() + .node("saturation", "use-inverse-color").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption SATURATION_COLOR = SimpleOption.builder() + .node("saturation", "saturation-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(255, 198, 0)) + .notifyClient() + .build(); + private ModSaturation() { } diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModScoreboard.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModScoreboard.java index 21a39371..45859cd9 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModScoreboard.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModScoreboard.java @@ -115,6 +115,18 @@ public final class ModScoreboard { .notifyClient() .build(); + /** + * Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + * + * @since 1.3.0 + */ + public static final SimpleOption LOCK_TO_VANILLA_POSITION = SimpleOption.builder() + .comment("Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on.") + .node("scoreboard", "lock-to-vanilla-position").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModSkyblock.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModSkyblock.java index c46082b9..b4b6d735 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModSkyblock.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModSkyblock.java @@ -190,6 +190,7 @@ public final class ModSkyblock { * * @since 1.2.5 */ + @Deprecated public static final SimpleOption CUSTOM_CHIME_VOLUME_ENABLED = SimpleOption.builder() .node("skyblock", "custom-chime-volume-enabled").type(TypeToken.get(Boolean.class)) .defaultValue(false) @@ -201,6 +202,7 @@ public final class ModSkyblock { * * @since 1.2.5 */ + @Deprecated public static final NumberOption CUSTOM_CHIME_VOLUME = NumberOption.number() .node("skyblock", "custom-chime-volume").type(TypeToken.get(Float.class)) .min(0.0F).max(1.0F) diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModTierTagger.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModTierTagger.java index a751c027..3533a4ba 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModTierTagger.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModTierTagger.java @@ -46,67 +46,25 @@ public final class ModTierTagger { .build(); /** - * No documentation available. + * Put the secondary tier on the left of the name and the primary tier on the right. * - * @since 1.1.9 + * @since 1.3.0 */ - public static final SimpleOption MC_TIERS_FORMAT = SimpleOption.builder() - .node("tier-tagger", "mc-tiers-format").type(TypeToken.get(Boolean.class)) - .defaultValue(false) - .notifyClient() - .build(); - - /** - * No documentation available. - * - * @since 1.1.9 - */ - public static final SimpleOption SUFFIX = SimpleOption.builder() - .node("tier-tagger", "suffix").type(TypeToken.get(Boolean.class)) + public static final SimpleOption SWITCH_ORDER = SimpleOption.builder() + .comment("Put the secondary tier on the left of the name and the primary tier on the right") + .node("tier-tagger", "switch-order").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() .build(); /** - * No documentation available. + * Put both tiers on one line above the nametag, instead of a line each. * - * @since 1.1.9 + * @since 1.3.0 */ - public static final SimpleOption SEPARATE_NAMETAG = SimpleOption.builder() - .node("tier-tagger", "separate-nametag").type(TypeToken.get(Boolean.class)) - .defaultValue(false) - .notifyClient() - .build(); - - /** - * No documentation available. - * - * @since 1.1.9 - */ - public static final SimpleOption SHOW_GM_ICONS = SimpleOption.builder() - .node("tier-tagger", "show-gm-icons").type(TypeToken.get(Boolean.class)) - .defaultValue(true) - .notifyClient() - .build(); - - /** - * No documentation available. - * - * @since 1.1.9 - */ - public static final SimpleOption SHOW_REGION = SimpleOption.builder() - .node("tier-tagger", "show-region").type(TypeToken.get(Boolean.class)) - .defaultValue(true) - .notifyClient() - .build(); - - /** - * No documentation available. - * - * @since 1.1.9 - */ - public static final SimpleOption SHOW_RETIRED = SimpleOption.builder() - .node("tier-tagger", "show-retired").type(TypeToken.get(Boolean.class)) + public static final SimpleOption COMBINE_SEPARATE_NAMETAGS = SimpleOption.builder() + .comment("Put both tiers on one line above the nametag, instead of a line each") + .node("tier-tagger", "combine-separate-nametags").type(TypeToken.get(Boolean.class)) .defaultValue(false) .notifyClient() .build(); @@ -276,6 +234,78 @@ public final class ModTierTagger { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.1.9 + */ + @Deprecated + public static final SimpleOption MC_TIERS_FORMAT = SimpleOption.builder() + .node("tier-tagger", "mc-tiers-format").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.1.9 + */ + @Deprecated + public static final SimpleOption SUFFIX = SimpleOption.builder() + .node("tier-tagger", "suffix").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.1.9 + */ + @Deprecated + public static final SimpleOption SEPARATE_NAMETAG = SimpleOption.builder() + .node("tier-tagger", "separate-nametag").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.1.9 + */ + @Deprecated + public static final SimpleOption SHOW_GM_ICONS = SimpleOption.builder() + .node("tier-tagger", "show-gm-icons").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.1.9 + */ + @Deprecated + public static final SimpleOption SHOW_REGION = SimpleOption.builder() + .node("tier-tagger", "show-region").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.1.9 + */ + @Deprecated + public static final SimpleOption SHOW_RETIRED = SimpleOption.builder() + .node("tier-tagger", "show-retired").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + private ModTierTagger() { } diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModTitles.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModTitles.java index d7f584be..c2b87436 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModTitles.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModTitles.java @@ -91,17 +91,6 @@ public final class ModTitles { .notifyClient() .build(); - /** - * No documentation available. - * - * @since 1.1.3 - */ - public static final SimpleOption USE_MINECRAFT_GUISCALE = SimpleOption.builder() - .node("titles", "use-minecraft-g-u-i-scale").type(TypeToken.get(Boolean.class)) - .defaultValue(true) - .notifyClient() - .build(); - /** * Keep the title centered around the center of the mod on-screen. * @@ -137,6 +126,30 @@ public final class ModTitles { .notifyClient() .build(); + /** + * Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + * + * @since 1.3.0 + */ + public static final SimpleOption LOCK_TO_VANILLA_POSITION = SimpleOption.builder() + .comment("Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on.") + .node("titles", "lock-to-vanilla-position").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale. + * + * @since 1.1.3 + */ + public static final SimpleOption USE_MINECRAFT_GUISCALE = SimpleOption.builder() + .comment("On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale.") + .node("titles", "use-minecraft-g-u-i-scale").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + private ModTitles() { } diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModToggleSneak.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModToggleSneak.java index 1e4e0df6..0503fe65 100644 --- a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModToggleSneak.java +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModToggleSneak.java @@ -56,6 +56,17 @@ public final class ModToggleSneak { .notifyClient() .build(); + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption ALWAYS_SPRINT = SimpleOption.builder() + .node("toggle-sneak", "always-sprint").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + /** * No documentation available. * @@ -134,6 +145,18 @@ public final class ModToggleSneak { .notifyClient() .build(); + /** + * Limits fly boost to Creative and Spectator. Turn off to use it in any mode where you can fly. + * + * @since 1.3.0 + */ + public static final SimpleOption RESTRICT_FLY_BOOST = SimpleOption.builder() + .comment("Limits fly boost to Creative and Spectator. Turn off to use it in any mode where you can fly.") + .node("toggle-sneak", "restrict-fly-boost").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + private ModToggleSneak() { } diff --git a/api/src/main/java/com/lunarclient/apollo/mods/impl/ModViewAngles.java b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModViewAngles.java new file mode 100644 index 00000000..32500770 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/mods/impl/ModViewAngles.java @@ -0,0 +1,372 @@ +/* + * This file is part of Apollo, licensed under the MIT License. + * + * Copyright (c) 2026 Moonsworth + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package com.lunarclient.apollo.mods.impl; + +import com.lunarclient.apollo.option.NumberOption; +import com.lunarclient.apollo.option.SimpleOption; +import io.leangen.geantyref.TypeToken; +import java.awt.Color; + +/** + * Display your yaw and pitch, with optional flight targets, speed, and altitude. + * + * @since 1.3.0 + */ +public final class ModViewAngles { + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption ENABLED = SimpleOption.builder() + .node("view-angles", "enabled").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption SCALE = NumberOption.number() + .node("view-angles", "scale").type(TypeToken.get(Float.class)) + .min(0.25F).max(5.0F) + .defaultValue(1.0F) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption DECIMAL_PLACES = NumberOption.number() + .node("view-angles", "decimal-places").type(TypeToken.get(Integer.class)) + .min(0).max(10) + .defaultValue(2) + .notifyClient() + .build(); + + /** + * Shows your left and right rotation. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_YAW = SimpleOption.builder() + .comment("Shows your left and right rotation.") + .node("view-angles", "show-yaw").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * Shows how far you look up or down. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_PITCH = SimpleOption.builder() + .comment("Shows how far you look up or down.") + .node("view-angles", "show-pitch").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption OPTIMAL_PITCH_INDICATOR = SimpleOption.builder() + .node("view-angles", "optimal-pitch-indicator").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption ASCEND_TARGET = NumberOption.number() + .node("view-angles", "ascend-target").type(TypeToken.get(Float.class)) + .min(-90.0F).max(0.0F) + .defaultValue(-40.0F) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption DESCEND_TARGET = NumberOption.number() + .node("view-angles", "descend-target").type(TypeToken.get(Float.class)) + .min(0.0F).max(90.0F) + .defaultValue(40.0F) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_SPEED = SimpleOption.builder() + .node("view-angles", "show-speed").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_ALTITUDE = SimpleOption.builder() + .node("view-angles", "show-altitude").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_IN_FIRST_PERSON = SimpleOption.builder() + .node("view-angles", "show-in-first-person").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_IN_THIRD_PERSON = SimpleOption.builder() + .node("view-angles", "show-in-third-person").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption SHOW_WHILE_ELYTRA_FLYING_ONLY = SimpleOption.builder() + .node("view-angles", "show-while-elytra-flying-only").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption REVERSE_ORDER = SimpleOption.builder() + .node("view-angles", "reverse-order").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * Adds a shadow to text. + * + * @since 1.3.0 + */ + public static final SimpleOption TEXT_SHADOW = SimpleOption.builder() + .comment("Adds a shadow to text") + .node("view-angles", "text-shadow").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BRACKETS = SimpleOption.builder() + .node("view-angles", "brackets").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BRACKET_COLOR = SimpleOption.builder() + .node("view-angles", "bracket-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(255, 255, 255)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BACKGROUND = SimpleOption.builder() + .node("view-angles", "background").type(TypeToken.get(Boolean.class)) + .defaultValue(true) + .notifyClient() + .build(); + + /** + * If this is disabled the background will change size with the text. + * + * @since 1.3.0 + */ + public static final SimpleOption STATIC_BACKGROUND_WIDTH = SimpleOption.builder() + .comment("If this is disabled the background will change size with the text.") + .node("view-angles", "static-background-width").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * If this is disabled the background will change size with the text. + * + * @since 1.3.0 + */ + public static final SimpleOption STATIC_BACKGROUND_HEIGHT = SimpleOption.builder() + .comment("If this is disabled the background will change size with the text.") + .node("view-angles", "static-background-height").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption BACKGROUND_WIDTH = NumberOption.number() + .node("view-angles", "background-width").type(TypeToken.get(Integer.class)) + .min(20).max(200) + .defaultValue(80) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption BACKGROUND_HEIGHT = NumberOption.number() + .node("view-angles", "background-height").type(TypeToken.get(Integer.class)) + .min(20).max(60) + .defaultValue(30) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BORDER = SimpleOption.builder() + .node("view-angles", "border").type(TypeToken.get(Boolean.class)) + .defaultValue(false) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final NumberOption BORDER_THICKNESS = NumberOption.number() + .node("view-angles", "border-thickness").type(TypeToken.get(Float.class)) + .min(0.5F).max(3.0F) + .defaultValue(0.5F) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BORDER_COLOR = SimpleOption.builder() + .node("view-angles", "border-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(0, 0, 0, 159)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption BACKGROUND_COLOR = SimpleOption.builder() + .node("view-angles", "background-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(0, 0, 0, 111)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption LABEL_COLOR = SimpleOption.builder() + .node("view-angles", "label-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(255, 170, 0)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption VALUE_COLOR = SimpleOption.builder() + .node("view-angles", "value-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(170, 170, 170)) + .notifyClient() + .build(); + + /** + * No documentation available. + * + * @since 1.3.0 + */ + public static final SimpleOption TEXT_COLOR = SimpleOption.builder() + .node("view-angles", "text-color").type(TypeToken.get(Color.class)) + .defaultValue(new Color(255, 255, 255)) + .notifyClient() + .build(); + + private ModViewAngles() { + } + +} diff --git a/docs/developers/mods/_meta.json b/docs/developers/mods/_meta.json index 1be56200..0106fbae 100644 --- a/docs/developers/mods/_meta.json +++ b/docs/developers/mods/_meta.json @@ -28,12 +28,14 @@ "freelook": "Freelook", "glintcolorizer": "GlintColorizer", "guiscale": "GuiScale", + "heightlimit": "HeightLimit", "hitbox": "Hitbox", "hitcolor": "HitColor", "horsestats": "HorseStats", "hurtcam": "HurtCam", "hypixelbedwars": "HypixelBedwars", "hypixelmod": "HypixelMod", + "hypixelstats": "HypixelStats", "inventorymod": "InventoryMod", "itemcounter": "ItemCounter", "itemcustomizer": "ItemCustomizer", @@ -44,6 +46,7 @@ "knockbacktrainer": "KnockbackTrainer", "lighting": "Lighting", "lightoverlay": "LightOverlay", + "locatorbar": "LocatorBar", "markers": "Markers", "memory": "Memory", "menublur": "MenuBlur", @@ -89,6 +92,7 @@ "tntcountdown": "TntCountdown", "togglesneak": "ToggleSneak", "totemcounter": "TotemCounter", + "viewangles": "ViewAngles", "waila": "Waila", "waypoints": "Waypoints", "weatherchanger": "WeatherChanger", diff --git a/docs/developers/mods/actionbar.mdx b/docs/developers/mods/actionbar.mdx index 2717694f..358bbdb3 100644 --- a/docs/developers/mods/actionbar.mdx +++ b/docs/developers/mods/actionbar.mdx @@ -29,3 +29,10 @@ public void toggleActionBarExample(Player viewer, boolean value) { - Minimum: `0.25F` - Maximum: `5.0F` +- __`LOCK_TO_VANILLA_POSITION`__ + - Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + - Config Key: `lock-to-vanilla-position` + - Values + - Type: `Boolean` + - Default: `false` + diff --git a/docs/developers/mods/armorstatus.mdx b/docs/developers/mods/armorstatus.mdx index d7b8e96f..f06f99b4 100644 --- a/docs/developers/mods/armorstatus.mdx +++ b/docs/developers/mods/armorstatus.mdx @@ -21,26 +21,36 @@ public void toggleArmorStatusExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `true` -- __`SCALE`__ - - Config Key: `scale` - - Values - - Type: `Float` - - Default: `1.0F` - - Minimum: `0.25F` - - Maximum: `5.0F` - - __`MOVE_ARMOR_INDIVIDUALLY`__ - Config Key: `move-armor-individually` - Values - Type: `Boolean` - Default: `false` -- __`HIDE_UNBREAKABLE_DURABILITY`__ - - Config Key: `hide-unbreakable-durability` +- __`VANILLA_MODE`__ + - Config Key: `vanilla-mode` + - Values + - Type: `Boolean` + - Default: `false` + +- __`HOTBAR_ANCHOR`__ + - Config Key: `hotbar-anchor` + - Values + - Type: `Boolean` + - Default: `true` + +- __`ROUNDED_CORNERS`__ + - Config Key: `rounded-corners` - Values - Type: `Boolean` - Default: `true` +- __`HIDE_EMPTY_SLOTS`__ + - Config Key: `hide-empty-slots` + - Values + - Type: `Boolean` + - Default: `false` + - __`ITEM_NAME`__ - Config Key: `item-name` - Values @@ -72,6 +82,12 @@ public void toggleArmorStatusExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` +- __`BACKGROUND_COLOR`__ + - Config Key: `background-color` + - Values + - Type: `String` + - Default: `#6F000000` + - __`BORDER`__ - Config Key: `border` - Values @@ -86,12 +102,40 @@ public void toggleArmorStatusExample(Player viewer, boolean value) { - Minimum: `0.5F` - Maximum: `3.0F` +- __`BORDER_COLOR`__ + - Config Key: `border-color` + - Values + - Type: `String` + - Default: `#9F000000` + +- __`SCALE`__ + - Config Key: `scale` + - Values + - Type: `Float` + - Default: `1.0F` + - Minimum: `0.25F` + - Maximum: `5.0F` + - __`DAMAGE_OVERLAY`__ - Config Key: `damage-overlay` - Values - Type: `Boolean` - Default: `true` +- __`LOW_DURABILITY_INDICATOR`__ + - Config Key: `low-durability-indicator` + - Values + - Type: `Boolean` + - Default: `true` + +- __`LOW_DURABILITY_THRESHOLD`__ + - Config Key: `low-durability-threshold` + - Values + - Type: `Integer` + - Default: `10` + - Minimum: `1` + - Maximum: `100` + - __`ITEM_DAMAGE`__ - Config Key: `item-damage` - Values @@ -110,23 +154,12 @@ public void toggleArmorStatusExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` -- __`BACKGROUND_COLOR`__ - - Config Key: `background-color` - - Values - - Type: `String` - - Default: `#6F000000` - -- __`BORDER_COLOR`__ - - Config Key: `border-color` - - Values - - Type: `String` - - Default: `#9F000000` - -- __`STATIC_DAMAGE_COLORS`__ - - Config Key: `static-damage-colors` +- __`HIDE_UNBREAKABLE_DURABILITY`__ + - Don't show damage value on items that are unbreakable + - Config Key: `hide-unbreakable-durability` - Values - Type: `Boolean` - - Default: `false` + - Default: `true` - __`NAME_TEXT_COLOR`__ - Config Key: `name-text-color` @@ -170,3 +203,9 @@ public void toggleArmorStatusExample(Player viewer, boolean value) { - Type: `String` - Default: `#FFAA0000` +- __`STATIC_DAMAGE_COLORS`__ + - Config Key: `static-damage-colors` + - Values + - Type: `Boolean` + - Default: `false` + diff --git a/docs/developers/mods/attackindicator.mdx b/docs/developers/mods/attackindicator.mdx index dc4b55af..b3c4746b 100644 --- a/docs/developers/mods/attackindicator.mdx +++ b/docs/developers/mods/attackindicator.mdx @@ -35,6 +35,13 @@ public void toggleAttackIndicatorExample(Player viewer, boolean value) { - Minimum: `0.25F` - Maximum: `5.0F` +- __`LOCK_TO_VANILLA_POSITION`__ + - Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + - Config Key: `lock-to-vanilla-position` + - Values + - Type: `Boolean` + - Default: `false` + - __`SHOW_IN_HUD_EDITOR`__ - Config Key: `show-in-hud-editor` - Values @@ -146,13 +153,6 @@ public void toggleAttackIndicatorExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` -- __`ATTACK_INDICATOR_PLAY_SOUND_VANILLA`__ - - Play a ding when the weapon cooldowns are done - - Config Key: `attack-indicator-play-sound-vanilla` - - Values - - Type: `Boolean` - - Default: `false` - - __`SLEEP`__ - Config Key: `sleep` - Values @@ -203,10 +203,3 @@ public void toggleAttackIndicatorExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` -- __`ATTACK_INDICATOR_PLAY_SOUND_CUSTOM`__ - - Play a ding when the cooldowns/indicators are done (excluding Sleep Progress, Block Breaking, Consumables and Storage Items) - - Config Key: `attack-indicator-play-sound-custom` - - Values - - Type: `Boolean` - - Default: `false` - diff --git a/docs/developers/mods/audiosubtitles.mdx b/docs/developers/mods/audiosubtitles.mdx index 649465b6..c0323df9 100644 --- a/docs/developers/mods/audiosubtitles.mdx +++ b/docs/developers/mods/audiosubtitles.mdx @@ -68,6 +68,13 @@ public void toggleAudioSubtitlesExample(Player viewer, boolean value) { - Type: `String` - Default: `#CC000000` +- __`LOCK_TO_VANILLA_POSITION`__ + - Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + - Config Key: `lock-to-vanilla-position` + - Values + - Type: `Boolean` + - Default: `false` + - __`TEXT_COLOR`__ - Config Key: `text-color` - Values diff --git a/docs/developers/mods/bossbar.mdx b/docs/developers/mods/bossbar.mdx index 70111a7f..7cfded44 100644 --- a/docs/developers/mods/bossbar.mdx +++ b/docs/developers/mods/bossbar.mdx @@ -53,7 +53,15 @@ public void toggleBossBarExample(Player viewer, boolean value) { - Type: `String` - Default: `#FFF249F2` +- __`LOCK_TO_VANILLA_POSITION`__ + - Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + - Config Key: `lock-to-vanilla-position` + - Values + - Type: `Boolean` + - Default: `false` + - __`USE_MINECRAFT_GUISCALE`__ + - On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale. - Config Key: `use-minecraft-g-u-i-scale` - Values - Type: `Boolean` diff --git a/docs/developers/mods/chat.mdx b/docs/developers/mods/chat.mdx index bf9fdc98..40723900 100644 --- a/docs/developers/mods/chat.mdx +++ b/docs/developers/mods/chat.mdx @@ -101,12 +101,6 @@ public void toggleChatExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `true` -- __`CHAT_PING_SOUND`__ - - Config Key: `chat-ping-sound` - - Values - - Type: `Boolean` - - Default: `true` - - __`CHAT_PING_EXACT_MATCH`__ - Requires the ping message to exactly contain your name. For example, if your name is Notch, this will ping on Notch but not Notch123. diff --git a/docs/developers/mods/coordinates.mdx b/docs/developers/mods/coordinates.mdx index b6e67268..ddf43e92 100644 --- a/docs/developers/mods/coordinates.mdx +++ b/docs/developers/mods/coordinates.mdx @@ -68,6 +68,14 @@ public void toggleCoordinatesExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` +- __`DECIMAL_PLACES`__ + - Config Key: `decimal-places` + - Values + - Type: `Integer` + - Default: `2` + - Minimum: `0` + - Maximum: `10` + - __`MOVE_CHILDREN_INDIVIDUALLY`__ - Config Key: `move-children-individually` - Values diff --git a/docs/developers/mods/damagetint.mdx b/docs/developers/mods/damagetint.mdx index 6b62726b..74604563 100644 --- a/docs/developers/mods/damagetint.mdx +++ b/docs/developers/mods/damagetint.mdx @@ -45,18 +45,3 @@ public void toggleDamageTintExample(Player viewer, boolean value) { - Minimum: `0` - Maximum: `100` -- __`HEARTBEAT_AUDIO`__ - - Plays a heartbeat, becoming faster the lower your health. - - Config Key: `heartbeat-audio` - - Values - - Type: `Boolean` - - Default: `false` - -- __`HEARTBEAT_AUDIO_VOLUME`__ - - Config Key: `heartbeat-audio-volume` - - Values - - Type: `Float` - - Default: `1.0F` - - Minimum: `0.0F` - - Maximum: `1.0F` - diff --git a/docs/developers/mods/guiscale.mdx b/docs/developers/mods/guiscale.mdx index 44c7964c..92b982a6 100644 --- a/docs/developers/mods/guiscale.mdx +++ b/docs/developers/mods/guiscale.mdx @@ -30,10 +30,11 @@ public void toggleGUIScaleExample(Player viewer, boolean value) { - Maximum: `2.0F` - __`INVENTORY_SCALE`__ + - 0 = Auto/Vanilla Handling - Config Key: `inventory-scale` - Values - Type: `Integer` - - Default: `2` - - Minimum: `1` + - Default: `0` + - Minimum: `0` - Maximum: `5` diff --git a/docs/developers/mods/heightlimit.mdx b/docs/developers/mods/heightlimit.mdx new file mode 100644 index 00000000..f724e8f8 --- /dev/null +++ b/docs/developers/mods/heightlimit.mdx @@ -0,0 +1,118 @@ +# Height Limit + +Block overlay and HUD display to help you build up to map height limits + +## Integration + +### How to toggle the mod + +```java +public void toggleHeightLimitExample(Player viewer, boolean value) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.modSettingModule.getOptions().set(apolloPlayer, ModHeightLimit.ENABLED, value)); +} +``` + +## Available options + +- __`ENABLED`__ + - Config Key: `enabled` + - Values + - Type: `Boolean` + - Default: `false` + +- __`SCALE`__ + - Config Key: `scale` + - Values + - Type: `Float` + - Default: `1.0F` + - Minimum: `0.25F` + - Maximum: `5.0F` + +- __`RENDER_RANGE`__ + - How far around you the block overlay is drawn + - Config Key: `render-range` + - Values + - Type: `Integer` + - Default: `4` + - Minimum: `1` + - Maximum: `8` + +- __`HEIGHT_LIMIT_OVERLAY`__ + - Display height limit information on the HUD + - Config Key: `height-limit-overlay` + - Values + - Type: `Boolean` + - Default: `true` + +- __`TEXT_SHADOW`__ + - Adds a shadow to text + - Config Key: `text-shadow` + - Values + - Type: `Boolean` + - Default: `true` + +- __`BACKGROUND`__ + - Config Key: `background` + - Values + - Type: `Boolean` + - Default: `true` + +- __`BORDER`__ + - Config Key: `border` + - Values + - Type: `Boolean` + - Default: `false` + +- __`BORDER_THICKNESS`__ + - Config Key: `border-thickness` + - Values + - Type: `Float` + - Default: `0.5F` + - Minimum: `0.5F` + - Maximum: `3.0F` + +- __`AUTO_ALIGN`__ + - Automatically determine text alignment from position. Disable to manually set alignment + - Config Key: `auto-align` + - Values + - Type: `Boolean` + - Default: `true` + +- __`AUTO_COLOR_DISTANCE`__ + - Distance changes color depending on how close you are to the height limit + - Config Key: `auto-color-distance` + - Values + - Type: `Boolean` + - Default: `true` + +- __`TITLE_COLOR`__ + - Config Key: `title-color` + - Values + - Type: `String` + - Default: `#FFFFFF55` + +- __`TEXT_COLOR`__ + - Config Key: `text-color` + - Values + - Type: `String` + - Default: `#FFFFFFFF` + +- __`NUMBER_COLOR`__ + - Config Key: `number-color` + - Values + - Type: `String` + - Default: `#FF55FF55` + +- __`BACKGROUND_COLOR`__ + - Config Key: `background-color` + - Values + - Type: `String` + - Default: `#6F000000` + +- __`BORDER_COLOR`__ + - Config Key: `border-color` + - Values + - Type: `String` + - Default: `#9F000000` + diff --git a/docs/developers/mods/hypixelstats.mdx b/docs/developers/mods/hypixelstats.mdx new file mode 100644 index 00000000..917bd6ee --- /dev/null +++ b/docs/developers/mods/hypixelstats.mdx @@ -0,0 +1,23 @@ +# Hypixel Stats + +Tracks stats across different Hypixel games. + +## Integration + +### How to toggle the mod + +```java +public void toggleHypixelStatsExample(Player viewer, boolean value) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.modSettingModule.getOptions().set(apolloPlayer, ModHypixelStats.ENABLED, value)); +} +``` + +## Available options + +- __`ENABLED`__ + - Config Key: `enabled` + - Values + - Type: `Boolean` + - Default: `false` + diff --git a/docs/developers/mods/inventorymod.mdx b/docs/developers/mods/inventorymod.mdx index c7af8c8f..6285ad45 100644 --- a/docs/developers/mods/inventorymod.mdx +++ b/docs/developers/mods/inventorymod.mdx @@ -36,3 +36,9 @@ public void toggleInventoryExample(Player viewer, boolean value) { - Minimum: `0.1F` - Maximum: `5.0F` +- __`CURSOR_RESET_CHEST_SCREENS_ONLY`__ + - Config Key: `cursor-reset-chest-screens-only` + - Values + - Type: `Boolean` + - Default: `true` + diff --git a/docs/developers/mods/knockbacktrainer.mdx b/docs/developers/mods/knockbacktrainer.mdx index 8dfc098c..3859f2f0 100644 --- a/docs/developers/mods/knockbacktrainer.mdx +++ b/docs/developers/mods/knockbacktrainer.mdx @@ -37,17 +37,3 @@ public void toggleKnockbackTrainerExample(Player viewer, boolean value) { - Minimum: `0` - Maximum: `10` -- __`FALLING_HIT_SOUND`__ - - Config Key: `falling-hit-sound` - - Values - - Type: `Boolean` - - Default: `true` - -- __`FALLING_HIT_SOUND_VOLUME`__ - - Config Key: `falling-hit-sound-volume` - - Values - - Type: `Float` - - Default: `1.0F` - - Minimum: `0.0F` - - Maximum: `1.0F` - diff --git a/docs/developers/mods/locatorbar.mdx b/docs/developers/mods/locatorbar.mdx new file mode 100644 index 00000000..65f9b450 --- /dev/null +++ b/docs/developers/mods/locatorbar.mdx @@ -0,0 +1,188 @@ +# Locator Bar + +Customize the locator bar's position, size, and displayed information. + +## Integration + +### How to toggle the mod + +```java +public void toggleLocatorBarExample(Player viewer, boolean value) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.modSettingModule.getOptions().set(apolloPlayer, ModLocatorBar.ENABLED, value)); +} +``` + +## Available options + +- __`ENABLED`__ + - Config Key: `enabled` + - Values + - Type: `Boolean` + - Default: `false` + +- __`HIDE_LOCATOR_BAR`__ + - Config Key: `hide-locator-bar` + - Values + - Type: `Boolean` + - Default: `false` + +- __`DETACHED`__ + - Move and scale the locator bar like a HUD mod instead of keeping it in the hotbar + - Config Key: `detached` + - Values + - Type: `Boolean` + - Default: `false` + +- __`SCALE`__ + - Config Key: `scale` + - Values + - Type: `Float` + - Default: `1.0F` + - Minimum: `0.5F` + - Maximum: `1.5F` + +- __`USE_PLAYER_HEADS`__ + - Draw the head of a player instead of the colored dot + - Config Key: `use-player-heads` + - Values + - Type: `Boolean` + - Default: `true` + +- __`PLAYER_HEAD_SCALE`__ + - Config Key: `player-head-scale` + - Values + - Type: `Float` + - Default: `1.0F` + - Minimum: `0.5F` + - Maximum: `2.0F` + +- __`PLAYER_HEAD_HIGHLIGHT`__ + - Draw an outline around the head with the dot color + - Config Key: `player-head-highlight` + - Values + - Type: `Boolean` + - Default: `true` + +- __`LIMIT_HEAD_RANGE`__ + - Players beyond the range show as the colored dot + - Config Key: `limit-head-range` + - Values + - Type: `Boolean` + - Default: `false` + +- __`PLAYER_HEAD_DISPLAY_RANGE`__ + - The maximum distance in blocks at which player heads show + - Config Key: `player-head-display-range` + - Values + - Type: `Integer` + - Default: `100` + - Minimum: `16` + - Maximum: `332` + +- __`SHOW_PLAYER_NAME`__ + - Config Key: `show-player-name` + - Values + - Type: `Boolean` + - Default: `false` + +- __`PLAYER_NAME_SCALE`__ + - Config Key: `player-name-scale` + - Values + - Type: `Float` + - Default: `1.0F` + - Minimum: `0.5F` + - Maximum: `1.0F` + +- __`ONLY_SHOW_NAME_WHEN_LOOKING_NEAR`__ + - Only draw the name of a player when you look toward them + - Config Key: `only-show-name-when-looking-near` + - Values + - Type: `Boolean` + - Default: `false` + +- __`LIMIT_NAME_RANGE`__ + - Only draw the names of players within the range + - Config Key: `limit-name-range` + - Values + - Type: `Boolean` + - Default: `false` + +- __`PLAYER_NAME_DISPLAY_RANGE`__ + - The maximum distance in blocks at which player names show + - Config Key: `player-name-display-range` + - Values + - Type: `Integer` + - Default: `100` + - Minimum: `16` + - Maximum: `332` + +- __`COLORED_PLAYER_NAME`__ + - Color the player name with their team color, or with their dot color when they have no team + - Config Key: `colored-player-name` + - Values + - Type: `Boolean` + - Default: `true` + +- __`HIDE_OVERLAPPING_NAMES`__ + - When names overlap, only draw the name closest to the middle of the bar + - Config Key: `hide-overlapping-names` + - Values + - Type: `Boolean` + - Default: `true` + +- __`CUT_LONG_NAMES`__ + - Cut names longer than 8 characters, but keep them different from other players + - Config Key: `cut-long-names` + - Values + - Type: `Boolean` + - Default: `true` + +- __`SHOW_DIRECTION`__ + - Config Key: `show-direction` + - Values + - Type: `Boolean` + - Default: `false` + +- __`USE_COORDINATE_DIRECTIONS`__ + - Show +Z, -Z, +X and -X instead of the direction letters + - Config Key: `use-coordinate-directions` + - Values + - Type: `Boolean` + - Default: `false` + +- __`SHOW_BAR_ICONS`__ + - Draw the dots or player heads. Turn this off to only show the names + - Config Key: `show-bar-icons` + - Values + - Type: `Boolean` + - Default: `true` + +- __`USE_XP_BAR`__ + - Draw the waypoints on the xp bar instead of the locator bar + - Config Key: `use-xp-bar` + - Values + - Type: `Boolean` + - Default: `false` + +- __`TEXT_SHADOW`__ + - Adds a shadow to text + - Config Key: `text-shadow` + - Values + - Type: `Boolean` + - Default: `true` + +- __`LOCATOR_BAR_PEEK`__ + - Only show the extra info while the peek keybind is held down + - Config Key: `locator-bar-peek` + - Values + - Type: `Boolean` + - Default: `false` + +- __`ONLY_SHOW_WHILE_PEEKING`__ + - Hide the locator bar until you hold the peek keybind + - Config Key: `only-show-while-peeking` + - Values + - Type: `Boolean` + - Default: `false` + diff --git a/docs/developers/mods/minimap.mdx b/docs/developers/mods/minimap.mdx index d785036d..8c8706dc 100644 --- a/docs/developers/mods/minimap.mdx +++ b/docs/developers/mods/minimap.mdx @@ -29,6 +29,15 @@ public void toggleMinimapExample(Player viewer, boolean value) { - Minimum: `0.25F` - Maximum: `5.0F` +- __`MINIMAP_SAVE_AS_PICTURE_FILE`__ + - Create a viewable image file on your pc of the discovered map areas. +For singleplayer, it's saved in the world folder +For Multiplayer, it's saved in the .minecraft folder + - Config Key: `minimap-save-as-picture-file` + - Values + - Type: `Boolean` + - Default: `false` + - __`MAP_WIDTH`__ - Config Key: `map-width` - Values diff --git a/docs/developers/mods/nickhider.mdx b/docs/developers/mods/nickhider.mdx index d49e7062..34c2e0b9 100644 --- a/docs/developers/mods/nickhider.mdx +++ b/docs/developers/mods/nickhider.mdx @@ -22,24 +22,28 @@ public void toggleNickHiderExample(Player viewer, boolean value) { - Default: `false` - __`HIDE_NAME`__ + - Replaces your Hypixel nick with your real name, or with your Nickname when Hide Your Real Name is on - Config Key: `hide-name` - Values - Type: `Boolean` - Default: `true` - __`HIDE_REAL_NAME`__ + - Replaces your real name with your Nickname - Config Key: `hide-real-name` - Values - Type: `Boolean` - Default: `true` - __`HIDE_OTHERS_NAMES`__ + - Replaces the names of other players with the Hidden Player Prefix and a number - Config Key: `hide-others-names` - Values - Type: `Boolean` - Default: `false` - __`CUSTOM_SUFFIX`__ + - Shows every hidden player as the prefix followed by the Hidden Player Suffix, instead of numbering them - Config Key: `custom-suffix` - Values - Type: `Boolean` @@ -52,18 +56,21 @@ public void toggleNickHiderExample(Player viewer, boolean value) { - Default: `false` - __`HIDE_OWN_SKIN`__ + - Shows you as Steve or Alex, or with a set skin from another player - Config Key: `hide-own-skin` - Values - Type: `Boolean` - - Default: `true` + - Default: `false` - __`USE_REAL_SKIN`__ + - Shows your own skin even when a server changes it, for example with a Hypixel nick - Config Key: `use-real-skin` - Values - Type: `Boolean` - Default: `true` - __`HIDE_OTHERS_SKIN`__ + - Shows other players as Steve or Alex - Config Key: `hide-others-skin` - Values - Type: `Boolean` diff --git a/docs/developers/mods/overlaymod.mdx b/docs/developers/mods/overlaymod.mdx index 7eb6fe84..29f6eac1 100644 --- a/docs/developers/mods/overlaymod.mdx +++ b/docs/developers/mods/overlaymod.mdx @@ -28,6 +28,13 @@ public void toggleOverlayExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` +- __`NO_MAP_BOBBING`__ + - Stop your hand from bobbing while holding a map. + - Config Key: `no-map-bobbing` + - Values + - Type: `Boolean` + - Default: `false` + - __`FIRE_HEIGHT`__ - Config Key: `fire-height` - Values @@ -76,6 +83,14 @@ public void toggleOverlayExample(Player viewer, boolean value) { - Minimum: `0.0F` - Maximum: `1.0F` +- __`FISHING_BOBBER_OVERLAY`__ + - Config Key: `fishing-bobber-overlay` + - Values + - Type: `Float` + - Default: `1.0F` + - Minimum: `0.0F` + - Maximum: `1.0F` + - __`HIDE_FOLIAGE`__ - Hides grass and double grass blocks - Config Key: `hide-foliage` @@ -278,7 +293,13 @@ public void toggleOverlayExample(Player viewer, boolean value) { - Config Key: `xp-orb-color` - Values - Type: `String` - - Default: `#80FFFFFF` + - Default: `#8080FF20` + +- __`XP_HOTBAR_TEXT_COLOR`__ + - Config Key: `xp-hotbar-text-color` + - Values + - Type: `String` + - Default: `#FF80FF20` - __`CUSTOM_FISHING_LINE`__ - Config Key: `custom-fishing-line` @@ -300,6 +321,42 @@ public void toggleOverlayExample(Player viewer, boolean value) { - Type: `String` - Default: `#FF000000` +- __`CUSTOM_GUI_COLORS`__ + - Config Key: `custom-gui-colors` + - Values + - Type: `Boolean` + - Default: `false` + +- __`CONTAINER_TINT`__ + - Config Key: `container-tint` + - Values + - Type: `String` + - Default: `#FF4B4B4B` + +- __`HOTBAR_TINT`__ + - Config Key: `hotbar-tint` + - Values + - Type: `String` + - Default: `#FF4B4B4B` + +- __`MENU_TINT`__ + - Config Key: `menu-tint` + - Values + - Type: `String` + - Default: `#FF4B4B4B` + +- __`GUI_TEXT_COLOR`__ + - Config Key: `gui-text-color` + - Values + - Type: `String` + - Default: `#FFD7D7D7` + +- __`MENU_TEXT_COLOR`__ + - Config Key: `menu-text-color` + - Values + - Type: `String` + - Default: `#FFD7D7D7` + - __`HEADLESS_HORSES`__ - Improve visibility when riding a horse - Config Key: `headless-horses` @@ -307,6 +364,18 @@ public void toggleOverlayExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` +- __`HEADLESS_LLAMAS`__ + - Config Key: `headless-l-lamas` + - Values + - Type: `Boolean` + - Default: `false` + +- __`HEADLESS_CAMELS`__ + - Config Key: `headless-camels` + - Values + - Type: `Boolean` + - Default: `false` + - __`DISABLE_DEATH_ANIMATION`__ - Config Key: `disable-death-animation` - Values diff --git a/docs/developers/mods/packdisplay.mdx b/docs/developers/mods/packdisplay.mdx index 4eea0bab..d33f9a80 100644 --- a/docs/developers/mods/packdisplay.mdx +++ b/docs/developers/mods/packdisplay.mdx @@ -53,6 +53,12 @@ public void togglePackDisplayExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `true` +- __`IGNORE_SERVER_PACK`__ + - Config Key: `ignore-server-pack` + - Values + - Type: `Boolean` + - Default: `false` + - __`TEXT_SHADOW`__ - Adds a shadow to text - Config Key: `text-shadow` diff --git a/docs/developers/mods/potioneffects.mdx b/docs/developers/mods/potioneffects.mdx index 568c098e..902e69bf 100644 --- a/docs/developers/mods/potioneffects.mdx +++ b/docs/developers/mods/potioneffects.mdx @@ -48,6 +48,13 @@ public void togglePotionEffectsExample(Player viewer, boolean value) { - Minimum: `1` - Maximum: `10` +- __`VANILLA_SPACING`__ + - Use the vanilla spacing between each effect tile + - Config Key: `vanilla-spacing` + - Values + - Type: `Boolean` + - Default: `false` + - __`MINIMAL_MODE_HORIZONTAL`__ - Config Key: `minimal-mode-horizontal` - Values @@ -80,11 +87,23 @@ public void togglePotionEffectsExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `true` -- __`SHOW_IN_INVENTORY`__ - - Config Key: `show-in-inventory` +- __`FORMATTED_DURATIONS`__ + - Config Key: `formatted-durations` - Values - Type: `Boolean` - - Default: `true` + - Default: `false` + +- __`UPPERCASE_POTION_NAMES`__ + - Config Key: `uppercase-potion-names` + - Values + - Type: `Boolean` + - Default: `false` + +- __`REVERSED_TEXT`__ + - Config Key: `reversed-text` + - Values + - Type: `Boolean` + - Default: `false` - __`SHOW_WHILE_TYPING`__ - Config Key: `show-while-typing` @@ -119,37 +138,76 @@ public void togglePotionEffectsExample(Player viewer, boolean value) { - Type: `String` - Default: `#FFFFFFFF` -- __`UPPERCASE_POTION_NAMES`__ - - Config Key: `uppercase-potion-names` +- __`SHOW_IN_INVENTORY`__ + - Config Key: `show-in-inventory` + - Values + - Type: `Boolean` + - Default: `true` + +- __`HIDE_MODERN_ICONS`__ + - Config Key: `hide-modern-icons` + - Values + - Type: `Boolean` + - Default: `true` + +- __`HIDE_POTION_STATUS`__ + - Completely hide the potion effects mod HUD + - Config Key: `hide-potion-status` - Values - Type: `Boolean` - Default: `false` -- __`REVERSED_TEXT`__ - - Config Key: `reversed-text` +- __`EFFECT_BARS`__ + - Show effect duration with a progress bar in the inventory/hud + - Config Key: `effect-bars` - Values - Type: `Boolean` - Default: `false` -- __`FORMATTED_DURATIONS`__ - - Config Key: `formatted-durations` +- __`EFFECT_BAR_VANILLA_HUD`__ + - Config Key: `effect-bar-vanilla-hud` + - Values + - Type: `Boolean` + - Default: `true` + +- __`EFFECT_BAR_INVENTORY`__ + - Config Key: `effect-bar-inventory` + - Values + - Type: `Boolean` + - Default: `true` + +- __`EFFECT_BAR_LUNAR_HUD`__ + - Show the duration bars on Lunar potion effect status huds + - Config Key: `effect-bar-lunar-hud` - Values - Type: `Boolean` - Default: `false` -- __`HIDE_MODERN_ICONS`__ - - Config Key: `hide-modern-icons` +- __`EFFECT_BAR_HIDE_AMBIENT`__ + - Config Key: `effect-bar-hide-ambient` - Values - Type: `Boolean` - Default: `true` -- __`HIDE_POTION_STATUS`__ - - Completely hide the potion effects mod HUD - - Config Key: `hide-potion-status` +- __`EFFECT_BAR_GRADIENT`__ + - Do a gradient animation on the bar color + - Config Key: `effect-bar-gradient` + - Values + - Type: `Boolean` + - Default: `true` + +- __`EFFECT_BAR_CUSTOM_COLOR`__ + - Config Key: `effect-bar-custom-color` - Values - Type: `Boolean` - Default: `false` +- __`EFFECT_BAR_COLOR`__ + - Config Key: `effect-bar-color` + - Values + - Type: `String` + - Default: `#FFFFFFFF` + - __`BACKGROUND`__ - Config Key: `background` - Values @@ -243,6 +301,20 @@ public void togglePotionEffectsExample(Player viewer, boolean value) { - Minimum: `0.25F` - Maximum: `5.0F` +- __`LOCK_TO_VANILLA_POSITION`__ + - Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + - Config Key: `lock-to-vanilla-position` + - Values + - Type: `Boolean` + - Default: `false` + +- __`USE_MINECRAFT_GUISCALE`__ + - On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale. + - Config Key: `use-minecraft-g-u-i-scale` + - Values + - Type: `Boolean` + - Default: `false` + - __`EXCLUDE_PERM`__ - Config Key: `exclude-perm` - Values diff --git a/docs/developers/mods/saturation.mdx b/docs/developers/mods/saturation.mdx index c16146ee..c5d64efa 100644 --- a/docs/developers/mods/saturation.mdx +++ b/docs/developers/mods/saturation.mdx @@ -27,12 +27,6 @@ public void toggleSaturationExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `true` -- __`SHOW_APPLESKIN_TOOLTIP`__ - - Config Key: `show-appleskin-tooltip` - - Values - - Type: `Boolean` - - Default: `true` - - __`SHOW_HELD_ITEM_HUNGER`__ - Config Key: `show-held-item-hunger` - Values @@ -45,3 +39,21 @@ public void toggleSaturationExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `true` +- __`SHOW_APPLESKIN_TOOLTIP`__ + - Config Key: `show-appleskin-tooltip` + - Values + - Type: `Boolean` + - Default: `true` + +- __`USE_INVERSE_COLOR`__ + - Config Key: `use-inverse-color` + - Values + - Type: `Boolean` + - Default: `false` + +- __`SATURATION_COLOR`__ + - Config Key: `saturation-color` + - Values + - Type: `String` + - Default: `#FFFFC600` + diff --git a/docs/developers/mods/scoreboard.mdx b/docs/developers/mods/scoreboard.mdx index 76dc26b6..ff0571a0 100644 --- a/docs/developers/mods/scoreboard.mdx +++ b/docs/developers/mods/scoreboard.mdx @@ -62,6 +62,13 @@ public void toggleScoreboardExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` +- __`LOCK_TO_VANILLA_POSITION`__ + - Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + - Config Key: `lock-to-vanilla-position` + - Values + - Type: `Boolean` + - Default: `false` + - __`DISPLAY_TOGGLE_MESSAGE`__ - Config Key: `display-toggle-message` - Values diff --git a/docs/developers/mods/skyblock.mdx b/docs/developers/mods/skyblock.mdx index a241c529..13006751 100644 --- a/docs/developers/mods/skyblock.mdx +++ b/docs/developers/mods/skyblock.mdx @@ -102,17 +102,3 @@ public void toggleHypixelSkyblockExample(Player viewer, boolean value) { - Minimum: `1.0F` - Maximum: `10.0F` -- __`CUSTOM_CHIME_VOLUME_ENABLED`__ - - Config Key: `custom-chime-volume-enabled` - - Values - - Type: `Boolean` - - Default: `false` - -- __`CUSTOM_CHIME_VOLUME`__ - - Config Key: `custom-chime-volume` - - Values - - Type: `Float` - - Default: `0.5F` - - Minimum: `0.0F` - - Maximum: `1.0F` - diff --git a/docs/developers/mods/tiertagger.mdx b/docs/developers/mods/tiertagger.mdx index 08fa2d9a..42a3b3ec 100644 --- a/docs/developers/mods/tiertagger.mdx +++ b/docs/developers/mods/tiertagger.mdx @@ -21,38 +21,16 @@ public void toggleTierTaggerExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `false` -- __`MC_TIERS_FORMAT`__ - - Config Key: `mc-tiers-format` +- __`SWITCH_ORDER`__ + - Put the secondary tier on the left of the name and the primary tier on the right + - Config Key: `switch-order` - Values - Type: `Boolean` - Default: `false` -- __`SUFFIX`__ - - Config Key: `suffix` - - Values - - Type: `Boolean` - - Default: `false` - -- __`SEPARATE_NAMETAG`__ - - Config Key: `separate-nametag` - - Values - - Type: `Boolean` - - Default: `false` - -- __`SHOW_GM_ICONS`__ - - Config Key: `show-gm-icons` - - Values - - Type: `Boolean` - - Default: `true` - -- __`SHOW_REGION`__ - - Config Key: `show-region` - - Values - - Type: `Boolean` - - Default: `true` - -- __`SHOW_RETIRED`__ - - Config Key: `show-retired` +- __`COMBINE_SEPARATE_NAMETAGS`__ + - Put both tiers on one line above the nametag, instead of a line each + - Config Key: `combine-separate-nametags` - Values - Type: `Boolean` - Default: `false` diff --git a/docs/developers/mods/titles.mdx b/docs/developers/mods/titles.mdx index 5eb98f30..26faf682 100644 --- a/docs/developers/mods/titles.mdx +++ b/docs/developers/mods/titles.mdx @@ -47,12 +47,6 @@ public void toggleTitlesExample(Player viewer, boolean value) { - Type: `String` - Default: `#FFFFFFFF` -- __`USE_MINECRAFT_GUISCALE`__ - - Config Key: `use-minecraft-g-u-i-scale` - - Values - - Type: `Boolean` - - Default: `true` - - __`KEEP_TITLE_CENTERED`__ - Keep the title centered around the center of the mod on-screen - Config Key: `keep-title-centered` @@ -73,3 +67,17 @@ public void toggleTitlesExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `true` +- __`LOCK_TO_VANILLA_POSITION`__ + - Keeps the mod at the vanilla position and scale. It can't be moved or scaled in the HUD editor while this is on. + - Config Key: `lock-to-vanilla-position` + - Values + - Type: `Boolean` + - Default: `false` + +- __`USE_MINECRAFT_GUISCALE`__ + - On always uses the Minecraft GUI scale for this mod, and Off always uses the Lunar UI scale. + - Config Key: `use-minecraft-g-u-i-scale` + - Values + - Type: `Boolean` + - Default: `true` + diff --git a/docs/developers/mods/togglesneak.mdx b/docs/developers/mods/togglesneak.mdx index 234deba4..0a2ac526 100644 --- a/docs/developers/mods/togglesneak.mdx +++ b/docs/developers/mods/togglesneak.mdx @@ -27,6 +27,12 @@ public void toggleToggleSneakSprintExample(Player viewer, boolean value) { - Type: `Boolean` - Default: `true` +- __`ALWAYS_SPRINT`__ + - Config Key: `always-sprint` + - Values + - Type: `Boolean` + - Default: `false` + - __`SPRINT_KEYBIND_OVERRIDE`__ - Config Key: `sprint-keybind-override` - Values @@ -71,3 +77,10 @@ public void toggleToggleSneakSprintExample(Player viewer, boolean value) { - Minimum: `2` - Maximum: `8` +- __`RESTRICT_FLY_BOOST`__ + - Limits fly boost to Creative and Spectator. Turn off to use it in any mode where you can fly. + - Config Key: `restrict-fly-boost` + - Values + - Type: `Boolean` + - Default: `true` + diff --git a/docs/developers/mods/viewangles.mdx b/docs/developers/mods/viewangles.mdx new file mode 100644 index 00000000..52c988bc --- /dev/null +++ b/docs/developers/mods/viewangles.mdx @@ -0,0 +1,210 @@ +# View Angles + +Display your yaw and pitch, with optional flight targets, speed, and altitude. + +## Integration + +### How to toggle the mod + +```java +public void toggleViewAnglesExample(Player viewer, boolean value) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(apolloPlayer -> this.modSettingModule.getOptions().set(apolloPlayer, ModViewAngles.ENABLED, value)); +} +``` + +## Available options + +- __`ENABLED`__ + - Config Key: `enabled` + - Values + - Type: `Boolean` + - Default: `false` + +- __`SCALE`__ + - Config Key: `scale` + - Values + - Type: `Float` + - Default: `1.0F` + - Minimum: `0.25F` + - Maximum: `5.0F` + +- __`DECIMAL_PLACES`__ + - Config Key: `decimal-places` + - Values + - Type: `Integer` + - Default: `2` + - Minimum: `0` + - Maximum: `10` + +- __`SHOW_YAW`__ + - Shows your left and right rotation. + - Config Key: `show-yaw` + - Values + - Type: `Boolean` + - Default: `true` + +- __`SHOW_PITCH`__ + - Shows how far you look up or down. + - Config Key: `show-pitch` + - Values + - Type: `Boolean` + - Default: `true` + +- __`OPTIMAL_PITCH_INDICATOR`__ + - Config Key: `optimal-pitch-indicator` + - Values + - Type: `Boolean` + - Default: `true` + +- __`ASCEND_TARGET`__ + - Config Key: `ascend-target` + - Values + - Type: `Float` + - Default: `-40.0F` + - Minimum: `-90.0F` + - Maximum: `0.0F` + +- __`DESCEND_TARGET`__ + - Config Key: `descend-target` + - Values + - Type: `Float` + - Default: `40.0F` + - Minimum: `0.0F` + - Maximum: `90.0F` + +- __`SHOW_SPEED`__ + - Config Key: `show-speed` + - Values + - Type: `Boolean` + - Default: `false` + +- __`SHOW_ALTITUDE`__ + - Config Key: `show-altitude` + - Values + - Type: `Boolean` + - Default: `false` + +- __`SHOW_IN_FIRST_PERSON`__ + - Config Key: `show-in-first-person` + - Values + - Type: `Boolean` + - Default: `true` + +- __`SHOW_IN_THIRD_PERSON`__ + - Config Key: `show-in-third-person` + - Values + - Type: `Boolean` + - Default: `true` + +- __`SHOW_WHILE_ELYTRA_FLYING_ONLY`__ + - Config Key: `show-while-elytra-flying-only` + - Values + - Type: `Boolean` + - Default: `false` + +- __`REVERSE_ORDER`__ + - Config Key: `reverse-order` + - Values + - Type: `Boolean` + - Default: `false` + +- __`TEXT_SHADOW`__ + - Adds a shadow to text + - Config Key: `text-shadow` + - Values + - Type: `Boolean` + - Default: `true` + +- __`BRACKETS`__ + - Config Key: `brackets` + - Values + - Type: `Boolean` + - Default: `true` + +- __`BRACKET_COLOR`__ + - Config Key: `bracket-color` + - Values + - Type: `String` + - Default: `#FFFFFFFF` + +- __`BACKGROUND`__ + - Config Key: `background` + - Values + - Type: `Boolean` + - Default: `true` + +- __`STATIC_BACKGROUND_WIDTH`__ + - If this is disabled the background will change size with the text. + - Config Key: `static-background-width` + - Values + - Type: `Boolean` + - Default: `false` + +- __`STATIC_BACKGROUND_HEIGHT`__ + - If this is disabled the background will change size with the text. + - Config Key: `static-background-height` + - Values + - Type: `Boolean` + - Default: `false` + +- __`BACKGROUND_WIDTH`__ + - Config Key: `background-width` + - Values + - Type: `Integer` + - Default: `80` + - Minimum: `20` + - Maximum: `200` + +- __`BACKGROUND_HEIGHT`__ + - Config Key: `background-height` + - Values + - Type: `Integer` + - Default: `30` + - Minimum: `20` + - Maximum: `60` + +- __`BORDER`__ + - Config Key: `border` + - Values + - Type: `Boolean` + - Default: `false` + +- __`BORDER_THICKNESS`__ + - Config Key: `border-thickness` + - Values + - Type: `Float` + - Default: `0.5F` + - Minimum: `0.5F` + - Maximum: `3.0F` + +- __`BORDER_COLOR`__ + - Config Key: `border-color` + - Values + - Type: `String` + - Default: `#9F000000` + +- __`BACKGROUND_COLOR`__ + - Config Key: `background-color` + - Values + - Type: `String` + - Default: `#6F000000` + +- __`LABEL_COLOR`__ + - Config Key: `label-color` + - Values + - Type: `String` + - Default: `#FFFFAA00` + +- __`VALUE_COLOR`__ + - Config Key: `value-color` + - Values + - Type: `String` + - Default: `#FFAAAAAA` + +- __`TEXT_COLOR`__ + - Config Key: `text-color` + - Values + - Type: `String` + - Default: `#FFFFFFFF` + From d4d241ddaf40c602a13611dfdde4172169d8af2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matej=20Bu=C4=8Dari=C4=87?= Date: Wed, 14 Oct 2026 22:15:46 +0200 Subject: [PATCH 6/6] Bump to 1.3.0 (#315) --- docs/developers/minestom.mdx | 6 +++--- example/bukkit/api/src/main/resources/plugin.yml | 2 +- example/bukkit/json/src/main/resources/plugin.yml | 2 +- example/bukkit/proto/src/main/resources/plugin.yml | 2 +- gradle.properties | 2 +- platform/bukkit/src/platform-loader/resources/plugin.yml | 2 +- platform/bungee/src/platform-loader/resources/plugin.yml | 2 +- platform/folia/src/main/resources/plugin.yml | 2 +- .../java/com/lunarclient/apollo/ApolloMinestomPlatform.java | 2 +- .../java/com/lunarclient/apollo/ApolloVelocityPlatform.java | 2 +- 10 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/developers/minestom.mdx b/docs/developers/minestom.mdx index 996eea83..d0208e48 100644 --- a/docs/developers/minestom.mdx +++ b/docs/developers/minestom.mdx @@ -52,14 +52,14 @@ Next, add the `apollo-minestom` dependency to your project. ```kotlin filename="build.gradle.kts" dependencies { - implementation("com.lunarclient:apollo-minestom:1.2.9") + implementation("com.lunarclient:apollo-minestom:1.3.0") } ``` ```groovy filename="build.gradle" dependencies { - implementation 'com.lunarclient:apollo-minestom:1.2.9' + implementation 'com.lunarclient:apollo-minestom:1.3.0' } ``` @@ -69,7 +69,7 @@ Next, add the `apollo-minestom` dependency to your project. com.lunarclient apollo-minestom - 1.2.9 + 1.3.0 compile diff --git a/example/bukkit/api/src/main/resources/plugin.yml b/example/bukkit/api/src/main/resources/plugin.yml index db41169d..90c03275 100644 --- a/example/bukkit/api/src/main/resources/plugin.yml +++ b/example/bukkit/api/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: Apollo-API-Example main: com.lunarclient.apollo.example.api.ApolloApiExamplePlatform -version: 1.2.9 +version: 1.3.0 author: Moonsworth softdepend: [ Apollo-Bukkit, Apollo-Folia ] api-version: 1.13 diff --git a/example/bukkit/json/src/main/resources/plugin.yml b/example/bukkit/json/src/main/resources/plugin.yml index f6a3c0c8..f3ee34de 100644 --- a/example/bukkit/json/src/main/resources/plugin.yml +++ b/example/bukkit/json/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: Apollo-Json-Example main: com.lunarclient.apollo.example.json.ApolloJsonExamplePlatform -version: 1.2.9 +version: 1.3.0 author: Moonsworth softdepend: [ Apollo-Bukkit ] api-version: 1.13 diff --git a/example/bukkit/proto/src/main/resources/plugin.yml b/example/bukkit/proto/src/main/resources/plugin.yml index 8cb0cbeb..85211bfd 100644 --- a/example/bukkit/proto/src/main/resources/plugin.yml +++ b/example/bukkit/proto/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: Apollo-Proto-Example main: com.lunarclient.apollo.example.proto.ApolloProtoExamplePlatform -version: 1.2.9 +version: 1.3.0 author: Moonsworth softdepend: [ Apollo-Bukkit ] api-version: 1.13 diff --git a/gradle.properties b/gradle.properties index 425cdaa5..95bd5e7d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ group=com.lunarclient -version=1.3.0-SNAPSHOT +version=1.3.0 description=The API for interacting with Lunar Client players. org.gradle.parallel=true diff --git a/platform/bukkit/src/platform-loader/resources/plugin.yml b/platform/bukkit/src/platform-loader/resources/plugin.yml index 914e6589..ba4310c5 100644 --- a/platform/bukkit/src/platform-loader/resources/plugin.yml +++ b/platform/bukkit/src/platform-loader/resources/plugin.yml @@ -1,6 +1,6 @@ name: Apollo-Bukkit main: com.lunarclient.apollo.loader.BukkitPlatformLoader -version: 1.2.9 +version: 1.3.0 author: Moonsworth api-version: 1.13 soft-depend: [LunarClient-API] diff --git a/platform/bungee/src/platform-loader/resources/plugin.yml b/platform/bungee/src/platform-loader/resources/plugin.yml index 633e3deb..b488fc60 100644 --- a/platform/bungee/src/platform-loader/resources/plugin.yml +++ b/platform/bungee/src/platform-loader/resources/plugin.yml @@ -1,4 +1,4 @@ name: Apollo-Bungee main: com.lunarclient.apollo.loader.BungeePlatformLoader -version: 1.2.9 +version: 1.3.0 author: Moonsworth diff --git a/platform/folia/src/main/resources/plugin.yml b/platform/folia/src/main/resources/plugin.yml index 3e38f5df..1f832d03 100644 --- a/platform/folia/src/main/resources/plugin.yml +++ b/platform/folia/src/main/resources/plugin.yml @@ -1,6 +1,6 @@ name: Apollo-Folia main: com.lunarclient.apollo.ApolloFoliaPlatform -version: 1.2.9 +version: 1.3.0 author: Moonsworth api-version: 1.13 folia-supported: true diff --git a/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java b/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java index 1c3a32e2..5bb8397b 100644 --- a/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java +++ b/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java @@ -256,7 +256,7 @@ public Options getOptions() { @Override public String getApolloVersion() { - return "1.2.9"; + return "1.3.0"; } @Override diff --git a/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java b/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java index 69bd2e43..ee33b784 100644 --- a/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java +++ b/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java @@ -119,7 +119,7 @@ @Plugin( id = "apollo", name = "Apollo-Velocity", - version = "1.2.9", + version = "1.3.0", url = "https://moonsworth.com", description = "Implementation of Apollo for Velocity", authors = {"Moonsworth"}