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());