diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/Marker.java b/api/src/main/java/com/lunarclient/apollo/module/marker/Marker.java new file mode 100644 index 00000000..1343d512 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/Marker.java @@ -0,0 +1,168 @@ +/* + * 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.marker; + +import com.lunarclient.apollo.common.location.ApolloLocation; +import com.lunarclient.apollo.module.marker.display.MarkerFlag; +import com.lunarclient.apollo.module.marker.target.BlockMarkerTarget; +import com.lunarclient.apollo.module.marker.target.EntityMarkerTarget; +import com.lunarclient.apollo.module.marker.target.ItemMarkerTarget; +import com.lunarclient.apollo.module.marker.target.MarkerTarget; +import com.lunarclient.apollo.module.marker.target.PlayerMarkerTarget; +import java.awt.Color; +import java.time.Duration; +import java.util.UUID; +import lombok.Builder; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Represents a marker which can be shown on the client. + * + * @since 1.2.8 + */ +@Getter +@Builder +public final class Marker { + + /** + * Returns the marker {@link String} id. + * + * @return the marker id + * @since 1.2.8 + */ + @NotNull String id; + + /** + * Returns the marker {@link ApolloLocation}. + * + * @return the marker location + * @since 1.2.8 + */ + @NotNull ApolloLocation location; + + /** + * Returns the marker owner's {@link UUID}. + * + *

Used to show the owner head.

+ * + * @return the owner uuid + * @since 1.2.8 + */ + @NotNull UUID ownerId; + + /** + * Returns the marker owner's {@link String} name. + * + * @return the owner name + * @since 1.2.8 + */ + @NotNull String ownerName; + + /** + * Returns the {@link MarkerFlag} (icon shape and base color) of this marker. + * + * @return the marker flag + * @since 1.2.8 + */ + @NotNull MarkerFlag flag; + + /** + * Returns the {@link Color} override for this marker's {@link #flag}. + * + *

Leave {@code null} to use the player's own configured color for the + * selected flag.

+ * + * @return the flag color override, or {@code null} to defer to the player's setting + * @since 1.2.8 + */ + @Builder.Default + @Nullable Color color = null; + + /** + * Returns the {@link MarkerTarget} describing what this marker marks. + * + *

Drives the description icon and text shown on the client. One of + * {@link ItemMarkerTarget}, {@link BlockMarkerTarget}, {@link EntityMarkerTarget} + * or {@link PlayerMarkerTarget}.

+ * + * @return the marker target + * @since 1.2.8 + */ + @NotNull MarkerTarget target; + + /** + * Returns the {@link Duration} the marker remains visible. + * + *

Leave {@code null} to defer to the player's configured marker + * duration.

+ * + * @return the duration, or {@code null} to defer to the player's setting + * @since 1.2.8 + */ + @Builder.Default + @Nullable Duration duration = null; + + /** + * Returns whether a popup notification is shown when this marker first appears. + * + * @return whether an in-game notification is shown + * @since 1.2.8 + */ + @Builder.Default + boolean inGameNotification = false; + + /** + * Returns whether a chat message is sent when this marker first appears. + * + * @return whether an in-game chat message is sent + * @since 1.2.8 + */ + @Builder.Default + boolean chatNotify = false; + + /** + * Returns whether the player can middle-click to remove this marker. + * + * @return the middle-click removal state + * @since 1.2.8 + */ + @Builder.Default + boolean middleClickRemove = true; + + /** + * Returns the {@link MarkerStyle} overrides applied to this marker. + * + *

Set to a built {@link MarkerStyle} to drive the marker's appearance + * from the server; leave {@code null} to defer entirely to the player's + * own Markers mod settings.

+ * + * @return the style overrides, or {@code null} when no override is sent + * @since 1.2.8 + */ + @Builder.Default + @Nullable MarkerStyle style = null; + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/MarkerModule.java b/api/src/main/java/com/lunarclient/apollo/module/marker/MarkerModule.java new file mode 100644 index 00000000..54d048ca --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/MarkerModule.java @@ -0,0 +1,75 @@ +/* + * 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.marker; + +import com.lunarclient.apollo.module.ApolloModule; +import com.lunarclient.apollo.module.ModuleDefinition; +import com.lunarclient.apollo.recipients.Recipients; +import org.jetbrains.annotations.ApiStatus; + +/** + * Represents the marker module. + * + * @since 1.2.8 + */ +@ApiStatus.NonExtendable +@ModuleDefinition(id = "marker", name = "Marker") +public abstract class MarkerModule extends ApolloModule { + + /** + * Displays the {@link Marker} to the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @param marker the marker + * @since 1.2.8 + */ + public abstract void displayMarker(Recipients recipients, Marker marker); + + /** + * Removes the {@link Marker} from the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @param markerId the marker id + * @since 1.2.8 + */ + public abstract void removeMarker(Recipients recipients, String markerId); + + /** + * Removes the {@link Marker} from the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @param marker the marker + * @since 1.2.8 + */ + public abstract void removeMarker(Recipients recipients, Marker marker); + + /** + * Resets all {@link Marker}s for the {@link Recipients}. + * + * @param recipients the recipients that are receiving the packet + * @since 1.2.8 + */ + public abstract void resetMarkers(Recipients recipients); + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/MarkerStyle.java b/api/src/main/java/com/lunarclient/apollo/module/marker/MarkerStyle.java new file mode 100644 index 00000000..aa96514b --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/MarkerStyle.java @@ -0,0 +1,138 @@ +/* + * 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.marker; + +import com.lunarclient.apollo.module.marker.display.MarkerDescriptionDisplay; +import com.lunarclient.apollo.module.marker.display.MarkerDisplayCondition; +import com.lunarclient.apollo.module.marker.display.MarkerOwnerDisplay; +import lombok.Builder; +import lombok.Getter; +import org.jetbrains.annotations.NotNull; + +/** + * Overrides for a marker's appearance, owner/description display and text on the Lunar client. + * + * @since 1.2.8 + */ +@Getter +@Builder +public final class MarkerStyle { + + /** + * The scale applied to the marker. + * + *

Accepts {@code 0.5F} to {@code 2.0F}.

+ * + * @since 1.2.8 + */ + @Builder.Default + float scale = 1.0F; + + /** + * Whether the marker plays its hover animations. + * + * @since 1.2.8 + */ + @Builder.Default + boolean animateMarkerOnHover = true; + + /** + * Whether the marker uses the compact single-row layout. + * + *

When {@code true}, {@link #ownerDisplay}, {@link #descriptionDisplay} and + * {@link #ownerSuffix} are ignored; the compact layout always uses the owner head, + * description icon and shows no suffix.

+ * + * @since 1.2.8 + */ + @Builder.Default + boolean compactMode = false; + + /** + * Whether a shadow is drawn behind the marker's text. + * + * @since 1.2.8 + */ + @Builder.Default + boolean textShadow = true; + + /** + * The suffix appended after the owner name. + * + *

Set to an empty {@link String} to show no suffix.

+ * + * @since 1.2.8 + */ + @Builder.Default + @NotNull String ownerSuffix = "'s Marker"; + + /** + * How the marker's owner is displayed. + * + * @since 1.2.8 + */ + @Builder.Default + @NotNull MarkerOwnerDisplay ownerDisplay = MarkerOwnerDisplay.HEAD; + + /** + * When the marker's owner is shown. + * + * @since 1.2.8 + */ + @Builder.Default + @NotNull MarkerDisplayCondition showOwner = MarkerDisplayCondition.ALWAYS; + + /** + * When the marker's coordinates are shown. + * + * @since 1.2.8 + */ + @Builder.Default + @NotNull MarkerDisplayCondition showCoordinates = MarkerDisplayCondition.NEVER; + + /** + * When the distance from the player to the marker is shown. + * + * @since 1.2.8 + */ + @Builder.Default + @NotNull MarkerDisplayCondition showDistance = MarkerDisplayCondition.HOVER; + + /** + * When the marker's description (what was marked) is shown. + * + * @since 1.2.8 + */ + @Builder.Default + @NotNull MarkerDisplayCondition showDescription = MarkerDisplayCondition.HOVER; + + /** + * How the marker's description is displayed. + * + * @since 1.2.8 + */ + @Builder.Default + @NotNull MarkerDescriptionDisplay descriptionDisplay = MarkerDescriptionDisplay.ICON; + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerDescriptionDisplay.java b/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerDescriptionDisplay.java new file mode 100644 index 00000000..9800bb52 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerDescriptionDisplay.java @@ -0,0 +1,35 @@ +/* + * 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.marker.display; + +/** + * Represents how a marker's description (what was marked) is displayed. + * + * @since 1.2.8 + */ +public enum MarkerDescriptionDisplay { + ICON, + TEXT + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerDisplayCondition.java b/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerDisplayCondition.java new file mode 100644 index 00000000..3ea829a0 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerDisplayCondition.java @@ -0,0 +1,36 @@ +/* + * 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.marker.display; + +/** + * Represents when part of a marker (owner, description, coordinates, distance) is shown. + * + * @since 1.2.8 + */ +public enum MarkerDisplayCondition { + NEVER, + HOVER, + ALWAYS + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerFlag.java b/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerFlag.java new file mode 100644 index 00000000..44a3ac8d --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerFlag.java @@ -0,0 +1,37 @@ +/* + * 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.marker.display; + +/** + * Represents a marker flag. + * + * @since 1.2.8 + */ +public enum MarkerFlag { + NORMAL, + DANGER, + INFO, + INTEREST + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerOwnerDisplay.java b/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerOwnerDisplay.java new file mode 100644 index 00000000..f90c467f --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/display/MarkerOwnerDisplay.java @@ -0,0 +1,35 @@ +/* + * 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.marker.display; + +/** + * Represents how a marker's owner is displayed. + * + * @since 1.2.8 + */ +public enum MarkerOwnerDisplay { + HEAD, + NAME + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/target/BlockMarkerTarget.java b/api/src/main/java/com/lunarclient/apollo/module/marker/target/BlockMarkerTarget.java new file mode 100644 index 00000000..d17234dd --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/target/BlockMarkerTarget.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.marker.target; + +import com.lunarclient.apollo.common.icon.ItemStackIcon; +import com.lunarclient.apollo.module.marker.Marker; +import lombok.Builder; +import lombok.Getter; + +/** + * Represents a {@link Marker} that marks a block. + * + * @since 1.2.8 + */ +@Getter +@Builder +public class BlockMarkerTarget extends MarkerTarget { + + /** + * Returns the {@link ItemStackIcon} of the marked block. + * + * @return the item stack icon + * @since 1.2.8 + */ + ItemStackIcon itemStack; + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/target/EntityMarkerTarget.java b/api/src/main/java/com/lunarclient/apollo/module/marker/target/EntityMarkerTarget.java new file mode 100644 index 00000000..bce76c00 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/target/EntityMarkerTarget.java @@ -0,0 +1,47 @@ +/* + * 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.marker.target; + +import com.lunarclient.apollo.module.marker.Marker; +import lombok.Builder; +import lombok.Getter; + +/** + * Represents a {@link Marker} that marks an entity. + * + * @since 1.2.8 + */ +@Getter +@Builder +public class EntityMarkerTarget extends MarkerTarget { + + /** + * Returns the marked entity type's registry name. + * + * @return the entity type registry name, e.g. {@code minecraft:zombie} + * @since 1.2.8 + */ + String entityType; + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/target/ItemMarkerTarget.java b/api/src/main/java/com/lunarclient/apollo/module/marker/target/ItemMarkerTarget.java new file mode 100644 index 00000000..3b1bd20a --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/target/ItemMarkerTarget.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.marker.target; + +import com.lunarclient.apollo.common.icon.ItemStackIcon; +import com.lunarclient.apollo.module.marker.Marker; +import lombok.Builder; +import lombok.Getter; + +/** + * Represents a {@link Marker} that marks an item. + * + * @since 1.2.8 + */ +@Getter +@Builder +public class ItemMarkerTarget extends MarkerTarget { + + /** + * Returns the {@link ItemStackIcon} of the marked item. + * + * @return the item stack icon + * @since 1.2.8 + */ + ItemStackIcon itemStack; + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/target/MarkerTarget.java b/api/src/main/java/com/lunarclient/apollo/module/marker/target/MarkerTarget.java new file mode 100644 index 00000000..133e2ef8 --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/target/MarkerTarget.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.marker.target; + +import com.lunarclient.apollo.module.marker.Marker; + +/** + * The abstract base class for what a {@link Marker} marks, which drives the description icon + * and text shown on the client. + * + *

Use one of {@link ItemMarkerTarget}, {@link BlockMarkerTarget}, {@link EntityMarkerTarget} + * or {@link PlayerMarkerTarget}.

+ * + * @since 1.2.8 + */ +public abstract class MarkerTarget { + +} diff --git a/api/src/main/java/com/lunarclient/apollo/module/marker/target/PlayerMarkerTarget.java b/api/src/main/java/com/lunarclient/apollo/module/marker/target/PlayerMarkerTarget.java new file mode 100644 index 00000000..cb069d8e --- /dev/null +++ b/api/src/main/java/com/lunarclient/apollo/module/marker/target/PlayerMarkerTarget.java @@ -0,0 +1,56 @@ +/* + * 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.marker.target; + +import com.lunarclient.apollo.module.marker.Marker; +import java.util.UUID; +import lombok.Builder; +import lombok.Getter; + +/** + * Represents a {@link Marker} that marks a player. + * + * @since 1.2.8 + */ +@Getter +@Builder +public class PlayerMarkerTarget extends MarkerTarget { + + /** + * Returns the marked player's {@link UUID}. + * + * @return the player uuid + * @since 1.2.8 + */ + UUID playerId; + + /** + * Returns the marked player's {@link String} name. + * + * @return the player name + * @since 1.2.8 + */ + String playerName; + +} diff --git a/common/src/main/java/com/lunarclient/apollo/module/marker/MarkerModuleImpl.java b/common/src/main/java/com/lunarclient/apollo/module/marker/MarkerModuleImpl.java new file mode 100644 index 00000000..ccd37cec --- /dev/null +++ b/common/src/main/java/com/lunarclient/apollo/module/marker/MarkerModuleImpl.java @@ -0,0 +1,219 @@ +/* + * 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.marker; + +import com.lunarclient.apollo.ApolloManager; +import com.lunarclient.apollo.marker.v1.BlockTarget; +import com.lunarclient.apollo.marker.v1.DangerMarker; +import com.lunarclient.apollo.marker.v1.DisplayMarkerMessage; +import com.lunarclient.apollo.marker.v1.EntityTarget; +import com.lunarclient.apollo.marker.v1.InfoMarker; +import com.lunarclient.apollo.marker.v1.InterestMarker; +import com.lunarclient.apollo.marker.v1.ItemTarget; +import com.lunarclient.apollo.marker.v1.NormalMarker; +import com.lunarclient.apollo.marker.v1.PlayerTarget; +import com.lunarclient.apollo.marker.v1.RemoveMarkerMessage; +import com.lunarclient.apollo.marker.v1.ResetMarkersMessage; +import com.lunarclient.apollo.module.marker.display.MarkerDescriptionDisplay; +import com.lunarclient.apollo.module.marker.display.MarkerDisplayCondition; +import com.lunarclient.apollo.module.marker.display.MarkerFlag; +import com.lunarclient.apollo.module.marker.display.MarkerOwnerDisplay; +import com.lunarclient.apollo.module.marker.target.BlockMarkerTarget; +import com.lunarclient.apollo.module.marker.target.EntityMarkerTarget; +import com.lunarclient.apollo.module.marker.target.ItemMarkerTarget; +import com.lunarclient.apollo.module.marker.target.MarkerTarget; +import com.lunarclient.apollo.module.marker.target.PlayerMarkerTarget; +import com.lunarclient.apollo.network.NetworkTypes; +import com.lunarclient.apollo.recipients.Recipients; +import java.awt.Color; +import java.time.Duration; +import lombok.NonNull; + +import static com.lunarclient.apollo.util.Ranges.checkRange; + +/** + * Provides the marker module. + * + * @since 1.2.8 + */ +public final class MarkerModuleImpl extends MarkerModule { + + @Override + public void displayMarker(@NonNull Recipients recipients, @NonNull Marker marker) { + DisplayMarkerMessage message = this.toProtobuf(marker); + ApolloManager.getNetworkManager().sendPacket(recipients, message); + } + + @Override + public void removeMarker(@NonNull Recipients recipients, @NonNull String markerId) { + RemoveMarkerMessage message = RemoveMarkerMessage.newBuilder() + .setId(markerId) + .build(); + + ApolloManager.getNetworkManager().sendPacket(recipients, message); + } + + @Override + public void removeMarker(@NonNull Recipients recipients, @NonNull Marker marker) { + this.removeMarker(recipients, marker.getId()); + } + + @Override + public void resetMarkers(@NonNull Recipients recipients) { + ResetMarkersMessage message = ResetMarkersMessage.getDefaultInstance(); + ApolloManager.getNetworkManager().sendPacket(recipients, message); + } + + private DisplayMarkerMessage toProtobuf(Marker marker) { + DisplayMarkerMessage.Builder builder = DisplayMarkerMessage.newBuilder() + .setId(marker.getId()) + .setLocation(NetworkTypes.toProtobuf(marker.getLocation())) + .setOwnerId(NetworkTypes.toProtobuf(marker.getOwnerId())) + .setOwnerName(marker.getOwnerName()) + .setInGameNotification(marker.isInGameNotification()) + .setChatNotify(marker.isChatNotify()) + .setMiddleClickRemove(marker.isMiddleClickRemove()); + + this.applyFlag(builder, marker.getFlag(), marker.getColor()); + builder.setTarget(this.toProtobuf(marker.getTarget())); + + Duration duration = marker.getDuration(); + if (duration != null) { + builder.setDuration(NetworkTypes.toProtobuf(duration)); + } + + MarkerStyle style = marker.getStyle(); + if (style != null) { + builder.setStyle(this.toProtobuf(style)); + } + + return builder.build(); + } + + private void applyFlag(DisplayMarkerMessage.Builder builder, MarkerFlag flag, Color color) { + com.lunarclient.apollo.common.v1.Color protoColor = color == null ? null : NetworkTypes.toProtobuf(color); + com.lunarclient.apollo.marker.v1.MarkerFlag.Builder flagBuilder = com.lunarclient.apollo.marker.v1.MarkerFlag.newBuilder(); + + switch (flag) { + case NORMAL: { + NormalMarker.Builder normal = NormalMarker.newBuilder(); + if (protoColor != null) { + normal.setColor(protoColor); + } + flagBuilder.setNormal(normal.build()); + break; + } + + case DANGER: { + DangerMarker.Builder danger = DangerMarker.newBuilder(); + if (protoColor != null) { + danger.setColor(protoColor); + } + flagBuilder.setDanger(danger.build()); + break; + } + + case INFO: { + InfoMarker.Builder info = InfoMarker.newBuilder(); + if (protoColor != null) { + info.setColor(protoColor); + } + flagBuilder.setInfo(info.build()); + break; + } + + case INTEREST: { + InterestMarker.Builder interest = InterestMarker.newBuilder(); + if (protoColor != null) { + interest.setColor(protoColor); + } + flagBuilder.setInterest(interest.build()); + break; + } + + default: { + throw new IllegalArgumentException("Unknown marker flag: " + flag); + } + } + + builder.setFlag(flagBuilder.build()); + } + + private com.lunarclient.apollo.marker.v1.MarkerTarget toProtobuf(MarkerTarget target) { + com.lunarclient.apollo.marker.v1.MarkerTarget.Builder builder = com.lunarclient.apollo.marker.v1.MarkerTarget.newBuilder(); + + if (target instanceof ItemMarkerTarget) { + builder.setItem(ItemTarget.newBuilder() + .setItemStack(NetworkTypes.toProtobuf(((ItemMarkerTarget) target).getItemStack())) + .build()); + } else if (target instanceof BlockMarkerTarget) { + builder.setBlock(BlockTarget.newBuilder() + .setItemStack(NetworkTypes.toProtobuf(((BlockMarkerTarget) target).getItemStack())) + .build()); + } else if (target instanceof EntityMarkerTarget) { + builder.setEntity(EntityTarget.newBuilder() + .setEntityType(((EntityMarkerTarget) target).getEntityType()) + .build()); + } else if (target instanceof PlayerMarkerTarget) { + PlayerMarkerTarget player = (PlayerMarkerTarget) target; + builder.setPlayer(PlayerTarget.newBuilder() + .setUuid(NetworkTypes.toProtobuf(player.getPlayerId())) + .setName(player.getPlayerName()) + .build()); + } else { + throw new IllegalArgumentException("Unknown marker target type: " + target.getClass().getName()); + } + + return builder.build(); + } + + private com.lunarclient.apollo.marker.v1.MarkerStyle toProtobuf(MarkerStyle style) { + return com.lunarclient.apollo.marker.v1.MarkerStyle.newBuilder() + .setScale(checkRange(style.getScale(), 0.5F, 2.0F, "MarkerStyle#scale")) + .setAnimateMarkerOnHover(style.isAnimateMarkerOnHover()) + .setCompactMode(style.isCompactMode()) + .setTextShadow(style.isTextShadow()) + .setOwnerSuffix(style.getOwnerSuffix()) + .setOwnerDisplay(this.toProtobuf(style.getOwnerDisplay())) + .setShowOwner(this.toProtobuf(style.getShowOwner())) + .setShowCoordinates(this.toProtobuf(style.getShowCoordinates())) + .setShowDistance(this.toProtobuf(style.getShowDistance())) + .setShowDescription(this.toProtobuf(style.getShowDescription())) + .setDescriptionDisplay(this.toProtobuf(style.getDescriptionDisplay())) + .build(); + } + + private com.lunarclient.apollo.marker.v1.MarkerDisplayCondition toProtobuf(MarkerDisplayCondition condition) { + return com.lunarclient.apollo.marker.v1.MarkerDisplayCondition.forNumber(condition.ordinal() + 1); + } + + private com.lunarclient.apollo.marker.v1.MarkerOwnerDisplay toProtobuf(MarkerOwnerDisplay display) { + return com.lunarclient.apollo.marker.v1.MarkerOwnerDisplay.forNumber(display.ordinal() + 1); + } + + private com.lunarclient.apollo.marker.v1.MarkerDescriptionDisplay toProtobuf(MarkerDescriptionDisplay display) { + return com.lunarclient.apollo.marker.v1.MarkerDescriptionDisplay.forNumber(display.ordinal() + 1); + } + +} diff --git a/docs/developers/modules/_meta.json b/docs/developers/modules/_meta.json index 1f3fba9c..182a8a35 100644 --- a/docs/developers/modules/_meta.json +++ b/docs/developers/modules/_meta.json @@ -12,6 +12,7 @@ "hologram": "Hologram", "inventory": "Inventory", "limb": "Limb", + "marker": "Marker", "modsetting": "Mod Setting", "nametag": "Nametag", "nickhider": "Nick Hider", diff --git a/docs/developers/modules/marker.mdx b/docs/developers/modules/marker.mdx new file mode 100644 index 00000000..de64861a --- /dev/null +++ b/docs/developers/modules/marker.mdx @@ -0,0 +1,688 @@ +import { Callout, Tab, Tabs } from 'nextra-theme-docs' + +# Marker Module + +## Overview + +The marker module allows you to place in-world markers from Lunar Client's Markers mod. + +- Place a marker at any exact location, attributed to any owner. +- Pick the marker flag (Normal, Danger, Info, Interest) and optionally override its color. +- Describe what is marked (an item, block, entity or player) to drive the marker's description icon and text. +- Override the appearance per marker + +![Marker Module Example](/modules/marker/overview.gif#center) + +
+ Create your own custom indicators using the Lunar Client Markers mod. +
+ +## Integration + +Explore each integration by cycling through each tab, to find the best fit for your requirements and needs. + +### Sample Code + + + + + + +**Apollo API examples.** See [General](/apollo/developers/general) for common patterns and helpers. + + +### Marking a block + +```java +public void displayBlockMarkerExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + Location location = viewer.getLocation(); + + this.markerModule.displayMarker(apolloPlayer, Marker.builder() + .id("loot-chest") + .location(ApolloLocation.builder() + .world(location.getWorld().getName()) + .x(location.getX()) + .y(location.getY()) + .z(location.getZ()) + .build()) + .ownerId(viewer.getUniqueId()) + .ownerName("") + .flag(MarkerFlag.INTEREST) + .target(BlockMarkerTarget.builder() + .itemStack(ItemStackIcon.builder().itemName("minecraft:chest").build()) + .build()) + .duration(Duration.ofSeconds(60)) + .style(MarkerStyle.builder() + .showOwner(MarkerDisplayCondition.NEVER) + .showDescription(MarkerDisplayCondition.ALWAYS) + .build()) + .build() + ); + }); +} +``` + +### Marking a player + +```java +public void displayPlayerMarkerExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + Location location = viewer.getLocation(); + + this.markerModule.displayMarker(apolloPlayer, Marker.builder() + .id("bounty") + .location(ApolloLocation.builder() + .world(location.getWorld().getName()) + .x(location.getX()) + .y(location.getY()) + .z(location.getZ()) + .build()) + .ownerId(viewer.getUniqueId()) + .ownerName(viewer.getName()) + .flag(MarkerFlag.DANGER) + .color(Color.RED) + .target(PlayerMarkerTarget.builder() + .playerId(UUID.fromString("f17627d8-1a97-487b-92ea-c04f413394bd")) + .playerName("ItsNature") + .build()) + .inGameNotification(true) + .style(MarkerStyle.builder() + .showOwner(MarkerDisplayCondition.NEVER) + .showDescription(MarkerDisplayCondition.ALWAYS) + .build()) + .build() + ); + }); +} +``` + +### Marking an item + +```java +public void displayItemMarkerExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + Location location = viewer.getLocation(); + + this.markerModule.displayMarker(apolloPlayer, Marker.builder() + .id("wither-loot") + .location(ApolloLocation.builder() + .world(location.getWorld().getName()) + .x(location.getX()) + .y(location.getY()) + .z(location.getZ()) + .build()) + .ownerId(viewer.getUniqueId()) + .ownerName(viewer.getName()) + .flag(MarkerFlag.INFO) + .target(ItemMarkerTarget.builder() + .itemStack(ItemStackIcon.builder().itemName("minecraft:nether_star").build()) + .build()) + .chatNotify(true) + .style(MarkerStyle.builder() + .showOwner(MarkerDisplayCondition.NEVER) + .showDescription(MarkerDisplayCondition.ALWAYS) + .build()) + .build() + ); + }); +} +``` + +### Marking an entity + +```java +public void displayEntityMarkerExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + Location location = viewer.getLocation(); + + this.markerModule.displayMarker(apolloPlayer, Marker.builder() + .id("tutorial-npc") + .location(ApolloLocation.builder() + .world(location.getWorld().getName()) + .x(location.getX()) + .y(location.getY()) + .z(location.getZ()) + .build()) + .ownerId(UUID.randomUUID()) + .ownerName("Tutorial NPC") + .flag(MarkerFlag.INTEREST) + .target(EntityMarkerTarget.builder() + .entityType("minecraft:villager") + .build()) + .style(MarkerStyle.builder() + .scale(1.3F) + .ownerSuffix("") + .ownerDisplay(MarkerOwnerDisplay.NAME) + .showOwner(MarkerDisplayCondition.HOVER) + .showDistance(MarkerDisplayCondition.NEVER) + .build()) + .build() + ); + }); +} +``` + +### Removing markers + +```java +public void removeMarkersExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + this.markerModule.removeMarker(apolloPlayer, "loot-chest"); + this.markerModule.removeMarker(apolloPlayer, "bounty"); + this.markerModule.removeMarker(apolloPlayer, "wither-loot"); + this.markerModule.removeMarker(apolloPlayer, "tutorial-npc"); + }); +} +``` + +### Resetting all markers + +```java +public void resetMarkersExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(this.markerModule::resetMarkers); +} +``` + +### `Marker` Options + +`.id(String)` should include a unique identifier for the marker. Re-sending a marker with an existing id updates it in place. + +```java +.id("loot-chest") +``` + +`.location(ApolloLocation)` is the exact location the marker is shown at. See the [locations utilities page](/apollo/developers/utilities/locations) for more. + +```java +.location(ApolloLocation.builder() + .world("world") + .x(0.5D) + .y(64.0D) + .z(0.5D) + .build() +) +``` + +`.ownerId(UUID)` and `.ownerName(String)` set the marker's owner. The owner's head is pulled from the player's tab list; if the owner is the viewing player they are shown as themselves. + +```java +.ownerId(viewer.getUniqueId()) +.ownerName(viewer.getName()) +``` + +`.flag(MarkerFlag)` is required and is the marker's flag, which sets its icon shape and base color. One of `NORMAL`, `DANGER`, `INFO`, `INTEREST`. + +```java +.flag(MarkerFlag.DANGER) +``` + +`.color(java.awt.Color)` overrides the color for the chosen flag. Supports alpha. Leave unset to use the player's own configured color for that flag. See the [colors page](/apollo/developers/utilities/colors) for more. + +```java +.color(Color.RED) +``` + +`.target(MarkerTarget)` is required and describes what is marked, which drives the description icon and text. Use an `ItemMarkerTarget` or `BlockMarkerTarget` (each wrapping an `ItemStackIcon` a block uses its item form), an `EntityMarkerTarget` (entity registry name) or a `PlayerMarkerTarget` (a player UUID + name). + +```java +.target(BlockMarkerTarget.builder() + .itemStack(ItemStackIcon.builder().itemName("minecraft:chest").build()) + .build()) +``` + +`.duration(java.time.Duration)` is how long the marker stays visible. Leave unset to defer to the player's configured marker visible-duration. + +```java +.duration(Duration.ofSeconds(60)) +``` + +`.inGameNotification(boolean)` shows a Lunar pop-up when the marker first appears. Defaults to `false`. + +```java +.inGameNotification(false) +``` + +`.chatNotify(boolean)` posts a chat message when the marker first appears. Defaults to `false`. + +```java +.chatNotify(false) +``` + +`.middleClickRemove(boolean)` lets the player middle-click the marker to remove it. Defaults to `true`. + +```java +.middleClickRemove(true) +``` + +`.style(MarkerStyle)` overrides the marker's appearance and text. Leave unset (or `null`) to defer entirely to the player's own Markers mod settings. + + +When `compactMode` is enabled the marker uses a compact single-row layout, and +`ownerDisplay`, `descriptionDisplay` and `ownerSuffix` are ignored. + + +```java +.style(MarkerStyle.builder() + .scale(1.0F) // 0.5F to 2.0F + .animateMarkerOnHover(true) + .compactMode(false) + .textShadow(true) + .ownerSuffix("'s Marker") // "" hides the suffix + .ownerDisplay(MarkerOwnerDisplay.HEAD) + .showOwner(MarkerDisplayCondition.ALWAYS) + .showCoordinates(MarkerDisplayCondition.NEVER) + .showDistance(MarkerDisplayCondition.HOVER) + .showDescription(MarkerDisplayCondition.HOVER) + .descriptionDisplay(MarkerDescriptionDisplay.ICON) + .build() +) +``` + + + + + + +**Lightweight Protobuf examples.** See [Lightweight Protobuf](/apollo/developers/lightweight/protobuf) for setup. + + + + Make sure the server is sending the world name to the client as shown in the [Player Detection](/apollo/developers/lightweight/protobuf/player-detection) example. + + +**Marking a block** + +```java +public void displayBlockMarkerExample(Player viewer) { + DisplayMarkerMessage message = DisplayMarkerMessage.newBuilder() + .setId("loot-chest") + .setLocation(ProtobufUtil.createLocationProto(viewer.getLocation())) + .setOwnerId(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .setOwnerName("") + .setFlag(MarkerFlag.newBuilder() + .setInterest(InterestMarker.getDefaultInstance()) + .build()) + .setTarget(MarkerTarget.newBuilder() + .setBlock(BlockTarget.newBuilder() + .setItemStack(ProtobufUtil.createItemStackIconProto("minecraft:chest", 0)) + .build()) + .build()) + .setDuration(ProtobufUtil.createDurationProto(Duration.ofSeconds(60))) + .setStyle(MarkerStyle.newBuilder() + .setScale(1.0F) + .setAnimateMarkerOnHover(true) + .setCompactMode(false) + .setTextShadow(true) + .setOwnerSuffix("'s Marker") + .setOwnerDisplay(MarkerOwnerDisplay.MARKER_OWNER_DISPLAY_HEAD) + .setShowOwner(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowCoordinates(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDistance(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setShowDescription(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_ALWAYS) + .setDescriptionDisplay(MarkerDescriptionDisplay.MARKER_DESCRIPTION_DISPLAY_ICON) + .build()) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + +**Marking a player** + +```java +public void displayPlayerMarkerExample(Player viewer) { + DisplayMarkerMessage message = DisplayMarkerMessage.newBuilder() + .setId("bounty") + .setLocation(ProtobufUtil.createLocationProto(viewer.getLocation())) + .setOwnerId(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .setOwnerName(viewer.getName()) + .setFlag(MarkerFlag.newBuilder() + .setDanger(DangerMarker.newBuilder() + .setColor(ProtobufUtil.createColorProto(Color.RED)) + .build()) + .build()) + .setTarget(MarkerTarget.newBuilder() + .setPlayer(PlayerTarget.newBuilder() + .setUuid(ProtobufUtil.createUuidProto(UUID.fromString("f17627d8-1a97-487b-92ea-c04f413394bd"))) + .setName("ItsNature") + .build()) + .build()) + .setInGameNotification(true) + .setStyle(MarkerStyle.newBuilder() + .setScale(1.0F) + .setAnimateMarkerOnHover(true) + .setCompactMode(false) + .setTextShadow(true) + .setOwnerSuffix("'s Marker") + .setOwnerDisplay(MarkerOwnerDisplay.MARKER_OWNER_DISPLAY_HEAD) + .setShowOwner(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowCoordinates(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDistance(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setShowDescription(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_ALWAYS) + .setDescriptionDisplay(MarkerDescriptionDisplay.MARKER_DESCRIPTION_DISPLAY_ICON) + .build()) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + +**Marking an item** + +```java +public void displayItemMarkerExample(Player viewer) { + DisplayMarkerMessage message = DisplayMarkerMessage.newBuilder() + .setId("wither-loot") + .setLocation(ProtobufUtil.createLocationProto(viewer.getLocation())) + .setOwnerId(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .setOwnerName(viewer.getName()) + .setFlag(MarkerFlag.newBuilder() + .setInfo(InfoMarker.getDefaultInstance()) + .build()) + .setTarget(MarkerTarget.newBuilder() + .setItem(ItemTarget.newBuilder() + .setItemStack(ProtobufUtil.createItemStackIconProto("minecraft:nether_star", 0)) + .build()) + .build()) + .setChatNotify(true) + .setStyle(MarkerStyle.newBuilder() + .setScale(1.0F) + .setAnimateMarkerOnHover(true) + .setCompactMode(false) + .setTextShadow(true) + .setOwnerSuffix("'s Marker") + .setOwnerDisplay(MarkerOwnerDisplay.MARKER_OWNER_DISPLAY_HEAD) + .setShowOwner(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowCoordinates(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDistance(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setShowDescription(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_ALWAYS) + .setDescriptionDisplay(MarkerDescriptionDisplay.MARKER_DESCRIPTION_DISPLAY_ICON) + .build()) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + +**Marking an entity** + +```java +public void displayEntityMarkerExample(Player viewer) { + DisplayMarkerMessage message = DisplayMarkerMessage.newBuilder() + .setId("tutorial-npc") + .setLocation(ProtobufUtil.createLocationProto(viewer.getLocation())) + .setOwnerId(ProtobufUtil.createUuidProto(UUID.randomUUID())) + .setOwnerName("Tutorial NPC") + .setFlag(MarkerFlag.newBuilder() + .setInterest(InterestMarker.getDefaultInstance()) + .build()) + .setTarget(MarkerTarget.newBuilder() + .setEntity(EntityTarget.newBuilder() + .setEntityType("minecraft:villager") + .build()) + .build()) + .setStyle(MarkerStyle.newBuilder() + .setScale(1.3F) + .setAnimateMarkerOnHover(true) + .setCompactMode(false) + .setTextShadow(true) + .setOwnerSuffix("") + .setOwnerDisplay(MarkerOwnerDisplay.MARKER_OWNER_DISPLAY_NAME) + .setShowOwner(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setShowCoordinates(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDistance(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDescription(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setDescriptionDisplay(MarkerDescriptionDisplay.MARKER_DESCRIPTION_DISPLAY_ICON) + .build()) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + +**Removing markers** + +```java +public void removeMarkersExample(Player viewer) { + List markerIds = Arrays.asList("loot-chest", "bounty", "wither-loot", "tutorial-npc"); + for (String id : markerIds) { + RemoveMarkerMessage message = RemoveMarkerMessage.newBuilder() + .setId(id) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } +} +``` + +**Resetting all markers** + +```java +public void resetMarkersExample(Player viewer) { + ResetMarkersMessage message = ResetMarkersMessage.getDefaultInstance(); + ProtobufPacketUtil.sendPacket(viewer, message); +} +``` + + + + + + +**Lightweight JSON examples.** See [Lightweight JSON](/apollo/developers/lightweight/json) for setup. + + + + Make sure the server is sending the world name to the client as shown in the [Player Detection](/apollo/developers/lightweight/json/player-detection) example. + + +**Marking a block** + +```java +public void displayBlockMarkerExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.DisplayMarkerMessage"); + message.addProperty("id", "loot-chest"); + message.add("location", JsonUtil.createLocationObject(viewer.getLocation())); + message.add("owner_id", JsonUtil.createUuidObject(viewer.getUniqueId())); + message.addProperty("owner_name", ""); + + JsonObject flag = new JsonObject(); + flag.add("interest", new JsonObject()); + message.add("flag", flag); + + JsonObject itemStack = new JsonObject(); + itemStack.addProperty("item_name", "minecraft:chest"); + JsonObject block = new JsonObject(); + block.add("item_stack", itemStack); + JsonObject target = new JsonObject(); + target.add("block", block); + message.add("target", target); + + message.addProperty("duration", JsonUtil.createDurationObject(Duration.ofSeconds(60))); + + JsonObject style = new JsonObject(); + style.addProperty("scale", 1.0F); + style.addProperty("animate_marker_on_hover", true); + style.addProperty("compact_mode", false); + style.addProperty("text_shadow", true); + style.addProperty("owner_suffix", "'s Marker"); + style.addProperty("owner_display", "MARKER_OWNER_DISPLAY_HEAD"); + style.addProperty("show_owner", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_coordinates", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_distance", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("show_description", "MARKER_DISPLAY_CONDITION_ALWAYS"); + style.addProperty("description_display", "MARKER_DESCRIPTION_DISPLAY_ICON"); + message.add("style", style); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + +**Marking a player** + +```java +public void displayPlayerMarkerExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.DisplayMarkerMessage"); + message.addProperty("id", "bounty"); + message.add("location", JsonUtil.createLocationObject(viewer.getLocation())); + message.add("owner_id", JsonUtil.createUuidObject(viewer.getUniqueId())); + message.addProperty("owner_name", viewer.getName()); + + JsonObject danger = new JsonObject(); + danger.add("color", JsonUtil.createColorObject(Color.RED)); + JsonObject flag = new JsonObject(); + flag.add("danger", danger); + message.add("flag", flag); + + JsonObject player = new JsonObject(); + player.add("uuid", JsonUtil.createUuidObject(UUID.fromString("f17627d8-1a97-487b-92ea-c04f413394bd"))); + player.addProperty("name", "ItsNature"); + JsonObject target = new JsonObject(); + target.add("player", player); + message.add("target", target); + + message.addProperty("in_game_notification", true); + + JsonObject style = new JsonObject(); + style.addProperty("scale", 1.0F); + style.addProperty("animate_marker_on_hover", true); + style.addProperty("compact_mode", false); + style.addProperty("text_shadow", true); + style.addProperty("owner_suffix", "'s Marker"); + style.addProperty("owner_display", "MARKER_OWNER_DISPLAY_HEAD"); + style.addProperty("show_owner", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_coordinates", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_distance", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("show_description", "MARKER_DISPLAY_CONDITION_ALWAYS"); + style.addProperty("description_display", "MARKER_DESCRIPTION_DISPLAY_ICON"); + message.add("style", style); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + +**Marking an item** + +```java +public void displayItemMarkerExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.DisplayMarkerMessage"); + message.addProperty("id", "wither-loot"); + message.add("location", JsonUtil.createLocationObject(viewer.getLocation())); + message.add("owner_id", JsonUtil.createUuidObject(viewer.getUniqueId())); + message.addProperty("owner_name", viewer.getName()); + + JsonObject flag = new JsonObject(); + flag.add("info", new JsonObject()); + message.add("flag", flag); + + JsonObject itemStack = new JsonObject(); + itemStack.addProperty("item_name", "minecraft:nether_star"); + JsonObject item = new JsonObject(); + item.add("item_stack", itemStack); + JsonObject target = new JsonObject(); + target.add("item", item); + message.add("target", target); + + message.addProperty("chat_notify", true); + + JsonObject style = new JsonObject(); + style.addProperty("scale", 1.0F); + style.addProperty("animate_marker_on_hover", true); + style.addProperty("compact_mode", false); + style.addProperty("text_shadow", true); + style.addProperty("owner_suffix", "'s Marker"); + style.addProperty("owner_display", "MARKER_OWNER_DISPLAY_HEAD"); + style.addProperty("show_owner", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_coordinates", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_distance", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("show_description", "MARKER_DISPLAY_CONDITION_ALWAYS"); + style.addProperty("description_display", "MARKER_DESCRIPTION_DISPLAY_ICON"); + message.add("style", style); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + +**Marking an entity** + +```java +public void displayEntityMarkerExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.DisplayMarkerMessage"); + message.addProperty("id", "tutorial-npc"); + message.add("location", JsonUtil.createLocationObject(viewer.getLocation())); + message.add("owner_id", JsonUtil.createUuidObject(UUID.randomUUID())); + message.addProperty("owner_name", "Tutorial NPC"); + + JsonObject flag = new JsonObject(); + flag.add("interest", new JsonObject()); + message.add("flag", flag); + + JsonObject entity = new JsonObject(); + entity.addProperty("entity_type", "minecraft:villager"); + JsonObject target = new JsonObject(); + target.add("entity", entity); + message.add("target", target); + + JsonObject style = new JsonObject(); + style.addProperty("scale", 1.3F); + style.addProperty("animate_marker_on_hover", true); + style.addProperty("compact_mode", false); + style.addProperty("text_shadow", true); + style.addProperty("owner_suffix", ""); + style.addProperty("owner_display", "MARKER_OWNER_DISPLAY_NAME"); + style.addProperty("show_owner", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("show_coordinates", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_distance", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_description", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("description_display", "MARKER_DESCRIPTION_DISPLAY_ICON"); + message.add("style", style); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + +**Removing markers** + +```java +public void removeMarkersExample(Player viewer) { + List markerIds = Arrays.asList("loot-chest", "bounty", "wither-loot", "tutorial-npc"); + for (String id : markerIds) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.RemoveMarkerMessage"); + message.addProperty("id", id); + + JsonPacketUtil.sendPacket(viewer, message); + } +} +``` + +**Resetting all markers** + +```java +public void resetMarkersExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.ResetMarkersMessage"); + + JsonPacketUtil.sendPacket(viewer, message); +} +``` + + + + diff --git a/docs/public/modules/marker/overview.gif b/docs/public/modules/marker/overview.gif new file mode 100644 index 00000000..a84d934e Binary files /dev/null and b/docs/public/modules/marker/overview.gif differ 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 5b26d6f8..2ae26a66 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 @@ -42,6 +42,7 @@ import com.lunarclient.apollo.example.api.module.GlowApiExample; import com.lunarclient.apollo.example.api.module.HologramApiExample; import com.lunarclient.apollo.example.api.module.LimbApiExample; +import com.lunarclient.apollo.example.api.module.MarkerApiExample; import com.lunarclient.apollo.example.api.module.ModSettingsApiExample; import com.lunarclient.apollo.example.api.module.NametagApiExample; import com.lunarclient.apollo.example.api.module.NickHiderApiExample; @@ -94,6 +95,7 @@ public void registerModuleExamples() { this.setGlowExample(new GlowApiExample()); this.setHologramExample(new HologramApiExample()); this.setLimbExample(new LimbApiExample()); + this.setMarkerExample(new MarkerApiExample()); this.setModSettingsExample(new ModSettingsApiExample()); this.setNametagExample(new NametagApiExample()); this.setNickHiderExample(new NickHiderApiExample()); diff --git a/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/MarkerApiExample.java b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/MarkerApiExample.java new file mode 100644 index 00000000..ce51ea85 --- /dev/null +++ b/example/bukkit/api/src/main/java/com/lunarclient/apollo/example/api/module/MarkerApiExample.java @@ -0,0 +1,203 @@ +/* + * 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.common.icon.ItemStackIcon; +import com.lunarclient.apollo.common.location.ApolloLocation; +import com.lunarclient.apollo.example.module.impl.MarkerExample; +import com.lunarclient.apollo.module.marker.Marker; +import com.lunarclient.apollo.module.marker.MarkerModule; +import com.lunarclient.apollo.module.marker.MarkerStyle; +import com.lunarclient.apollo.module.marker.display.MarkerDisplayCondition; +import com.lunarclient.apollo.module.marker.display.MarkerFlag; +import com.lunarclient.apollo.module.marker.display.MarkerOwnerDisplay; +import com.lunarclient.apollo.module.marker.target.BlockMarkerTarget; +import com.lunarclient.apollo.module.marker.target.EntityMarkerTarget; +import com.lunarclient.apollo.module.marker.target.ItemMarkerTarget; +import com.lunarclient.apollo.module.marker.target.PlayerMarkerTarget; +import com.lunarclient.apollo.player.ApolloPlayer; +import java.awt.Color; +import java.time.Duration; +import java.util.Optional; +import java.util.UUID; +import org.bukkit.Location; +import org.bukkit.entity.Player; + +public class MarkerApiExample extends MarkerExample { + + private final MarkerModule markerModule = Apollo.getModuleManager().getModule(MarkerModule.class); + + @Override + public void displayBlockMarkerExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + Location location = viewer.getLocation(); + + this.markerModule.displayMarker(apolloPlayer, Marker.builder() + .id("loot-chest") + .location(ApolloLocation.builder() + .world(location.getWorld().getName()) + .x(location.getX()) + .y(location.getY()) + .z(location.getZ()) + .build()) + .ownerId(viewer.getUniqueId()) + .ownerName("") + .flag(MarkerFlag.INTEREST) + .target(BlockMarkerTarget.builder() + .itemStack(ItemStackIcon + .builder() + .itemName("minecraft:chest") + .build()) + .build()) + .duration(Duration.ofSeconds(60)) + .style(MarkerStyle.builder() + .showOwner(MarkerDisplayCondition.NEVER) + .showDescription(MarkerDisplayCondition.ALWAYS) + .build()) + .build() + ); + }); + } + + @Override + public void displayPlayerMarkerExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + Location location = viewer.getLocation(); + + this.markerModule.displayMarker(apolloPlayer, Marker.builder() + .id("bounty") + .location(ApolloLocation.builder() + .world(location.getWorld().getName()) + .x(location.getX()) + .y(location.getY()) + .z(location.getZ()) + .build()) + .ownerId(viewer.getUniqueId()) + .ownerName(viewer.getName()) + .flag(MarkerFlag.DANGER) + .color(Color.RED) + .target(PlayerMarkerTarget.builder() + .playerId(UUID.fromString("f17627d8-1a97-487b-92ea-c04f413394bd")) + .playerName("ItsNature") + .build()) + .inGameNotification(true) + .style(MarkerStyle.builder() + .showOwner(MarkerDisplayCondition.NEVER) + .showDescription(MarkerDisplayCondition.ALWAYS) + .build()) + .build() + ); + }); + } + + @Override + public void displayItemMarkerExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + Location location = viewer.getLocation(); + + this.markerModule.displayMarker(apolloPlayer, Marker.builder() + .id("wither-loot") + .location(ApolloLocation.builder() + .world(location.getWorld().getName()) + .x(location.getX()) + .y(location.getY()) + .z(location.getZ()) + .build()) + .ownerId(viewer.getUniqueId()) + .ownerName(viewer.getName()) + .flag(MarkerFlag.INFO) + .target(ItemMarkerTarget.builder() + .itemStack(ItemStackIcon + .builder() + .itemName("minecraft:nether_star") + .build()) + .build()) + .style(MarkerStyle.builder() + .showOwner(MarkerDisplayCondition.NEVER) + .showDescription(MarkerDisplayCondition.ALWAYS) + .build()) + .build() + ); + }); + } + + @Override + public void displayEntityMarkerExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + Location location = viewer.getLocation(); + + this.markerModule.displayMarker(apolloPlayer, Marker.builder() + .id("tutorial-npc") + .location(ApolloLocation.builder() + .world(location.getWorld().getName()) + .x(location.getX()) + .y(location.getY()) + .z(location.getZ()) + .build()) + .ownerId(UUID.randomUUID()) + .ownerName("Tutorial NPC") + .flag(MarkerFlag.INTEREST) + .target(EntityMarkerTarget.builder() + .entityType("minecraft:villager") + .build()) + .style(MarkerStyle.builder() + .scale(1.3F) + .ownerSuffix("") + .ownerDisplay(MarkerOwnerDisplay.NAME) + .showOwner(MarkerDisplayCondition.HOVER) + .showDistance(MarkerDisplayCondition.NEVER) + .build()) + .build() + ); + }); + } + + @Override + public void removeMarkersExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + + apolloPlayerOpt.ifPresent(apolloPlayer -> { + this.markerModule.removeMarker(apolloPlayer, "loot-chest"); + this.markerModule.removeMarker(apolloPlayer, "bounty"); + this.markerModule.removeMarker(apolloPlayer, "wither-loot"); + this.markerModule.removeMarker(apolloPlayer, "tutorial-npc"); + }); + } + + @Override + public void resetMarkersExample(Player viewer) { + Optional apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId()); + apolloPlayerOpt.ifPresent(this.markerModule::resetMarkers); + } + +} diff --git a/example/bukkit/api/src/main/resources/plugin.yml b/example/bukkit/api/src/main/resources/plugin.yml index 9bc92e8b..57422037 100644 --- a/example/bukkit/api/src/main/resources/plugin.yml +++ b/example/bukkit/api/src/main/resources/plugin.yml @@ -42,6 +42,8 @@ commands: description: "Inventory!" limb: description: "Limb!" + marker: + description: "Markers!" modsettings: description: "ModSettings!" nametag: 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 9d29803e..c39d80f2 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 @@ -37,6 +37,7 @@ import com.lunarclient.apollo.example.command.HologramCommand; import com.lunarclient.apollo.example.command.InventoryCommand; import com.lunarclient.apollo.example.command.LimbCommand; +import com.lunarclient.apollo.example.command.MarkerCommand; import com.lunarclient.apollo.example.command.ModSettingsCommand; import com.lunarclient.apollo.example.command.NametagCommand; import com.lunarclient.apollo.example.command.NickHiderCommand; @@ -70,6 +71,7 @@ import com.lunarclient.apollo.example.module.impl.HologramExample; import com.lunarclient.apollo.example.module.impl.InventoryExample; import com.lunarclient.apollo.example.module.impl.LimbExample; +import com.lunarclient.apollo.example.module.impl.MarkerExample; import com.lunarclient.apollo.example.module.impl.ModSettingsExample; import com.lunarclient.apollo.example.module.impl.NametagExample; import com.lunarclient.apollo.example.module.impl.NickHiderExample; @@ -115,6 +117,7 @@ public abstract class ApolloExamplePlugin extends JavaPlugin { private HologramExample hologramExample; private InventoryExample inventoryExample; private LimbExample limbExample; + private MarkerExample markerExample; private ModSettingsExample modSettingsExample; private NametagExample nametagExample; private NickHiderExample nickHiderExample; @@ -173,6 +176,7 @@ private void registerCommonCommands() { this.getCommand("hologram").setExecutor(new HologramCommand()); this.getCommand("inventory").setExecutor(new InventoryCommand()); this.getCommand("limb").setExecutor(new LimbCommand()); + this.getCommand("marker").setExecutor(new MarkerCommand()); this.getCommand("modsettings").setExecutor(new ModSettingsCommand()); this.getCommand("nametag").setExecutor(new NametagCommand()); this.getCommand("nickhider").setExecutor(new NickHiderCommand()); diff --git a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/MarkerCommand.java b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/MarkerCommand.java new file mode 100644 index 00000000..c62b6a1f --- /dev/null +++ b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/command/MarkerCommand.java @@ -0,0 +1,97 @@ +/* + * 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.MarkerExample; +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 MarkerCommand 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; + + if (args.length != 1) { + player.sendMessage("Usage: /marker "); + return true; + } + + MarkerExample markerExample = ApolloExamplePlugin.getInstance().getMarkerExample(); + + switch (args[0].toLowerCase()) { + case "chest": { + markerExample.displayBlockMarkerExample(player); + player.sendMessage("Marking a block...."); + break; + } + + case "player": { + markerExample.displayPlayerMarkerExample(player); + player.sendMessage("Marking a player...."); + break; + } + + case "item": { + markerExample.displayItemMarkerExample(player); + player.sendMessage("Marking an item...."); + break; + } + + case "entity": { + markerExample.displayEntityMarkerExample(player); + player.sendMessage("Marking an entity...."); + break; + } + + case "remove": { + markerExample.removeMarkersExample(player); + player.sendMessage("Removing markers...."); + break; + } + + case "reset": { + markerExample.resetMarkersExample(player); + player.sendMessage("Resetting markers..."); + break; + } + + default: { + player.sendMessage("Usage: /marker "); + break; + } + } + + return true; + } +} diff --git a/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/MarkerExample.java b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/MarkerExample.java new file mode 100644 index 00000000..14b91cf0 --- /dev/null +++ b/example/bukkit/common/src/main/java/com/lunarclient/apollo/example/module/impl/MarkerExample.java @@ -0,0 +1,43 @@ +/* + * 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 MarkerExample extends ApolloModuleExample { + + public abstract void displayBlockMarkerExample(Player viewer); + + public abstract void displayPlayerMarkerExample(Player viewer); + + public abstract void displayItemMarkerExample(Player viewer); + + public abstract void displayEntityMarkerExample(Player viewer); + + public abstract void removeMarkersExample(Player viewer); + + public abstract void resetMarkersExample(Player viewer); + +} 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 7240c067..391c46d7 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 @@ -38,6 +38,7 @@ import com.lunarclient.apollo.example.json.module.GlowJsonExample; import com.lunarclient.apollo.example.json.module.HologramJsonExample; import com.lunarclient.apollo.example.json.module.LimbJsonExample; +import com.lunarclient.apollo.example.json.module.MarkerJsonExample; import com.lunarclient.apollo.example.json.module.ModSettingsJsonExample; import com.lunarclient.apollo.example.json.module.NametagJsonExample; import com.lunarclient.apollo.example.json.module.NickHiderJsonExample; @@ -82,6 +83,7 @@ public void registerModuleExamples() { this.setGlowExample(new GlowJsonExample()); this.setHologramExample(new HologramJsonExample()); this.setLimbExample(new LimbJsonExample()); + this.setMarkerExample(new MarkerJsonExample()); this.setModSettingsExample(new ModSettingsJsonExample()); this.setNametagExample(new NametagJsonExample()); this.setNickHiderExample(new NickHiderJsonExample()); diff --git a/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/MarkerJsonExample.java b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/MarkerJsonExample.java new file mode 100644 index 00000000..80b6f260 --- /dev/null +++ b/example/bukkit/json/src/main/java/com/lunarclient/apollo/example/json/module/MarkerJsonExample.java @@ -0,0 +1,216 @@ +/* + * 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.JsonObject; +import com.lunarclient.apollo.example.json.util.JsonPacketUtil; +import com.lunarclient.apollo.example.json.util.JsonUtil; +import com.lunarclient.apollo.example.module.impl.MarkerExample; +import java.awt.Color; +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import org.bukkit.entity.Player; + +public class MarkerJsonExample extends MarkerExample { + + @Override + public void displayBlockMarkerExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.DisplayMarkerMessage"); + message.addProperty("id", "loot-chest"); + message.add("location", JsonUtil.createLocationObject(viewer.getLocation())); + message.add("owner_id", JsonUtil.createUuidObject(viewer.getUniqueId())); + message.addProperty("owner_name", ""); + + JsonObject flag = new JsonObject(); + flag.add("interest", new JsonObject()); + message.add("flag", flag); + + JsonObject itemStack = new JsonObject(); + itemStack.addProperty("item_name", "minecraft:chest"); + JsonObject block = new JsonObject(); + block.add("item_stack", itemStack); + JsonObject target = new JsonObject(); + target.add("block", block); + message.add("target", target); + + message.addProperty("duration", JsonUtil.createDurationObject(Duration.ofSeconds(60))); + + JsonObject style = new JsonObject(); + style.addProperty("scale", 1.0F); + style.addProperty("animate_marker_on_hover", true); + style.addProperty("compact_mode", false); + style.addProperty("text_shadow", true); + style.addProperty("owner_suffix", "'s Marker"); + style.addProperty("owner_display", "MARKER_OWNER_DISPLAY_HEAD"); + style.addProperty("show_owner", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_coordinates", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_distance", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("show_description", "MARKER_DISPLAY_CONDITION_ALWAYS"); + style.addProperty("description_display", "MARKER_DESCRIPTION_DISPLAY_ICON"); + message.add("style", style); + + JsonPacketUtil.sendPacket(viewer, message); + } + + @Override + public void displayPlayerMarkerExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.DisplayMarkerMessage"); + message.addProperty("id", "bounty"); + message.add("location", JsonUtil.createLocationObject(viewer.getLocation())); + message.add("owner_id", JsonUtil.createUuidObject(viewer.getUniqueId())); + message.addProperty("owner_name", viewer.getName()); + + JsonObject danger = new JsonObject(); + danger.add("color", JsonUtil.createColorObject(Color.RED)); + JsonObject flag = new JsonObject(); + flag.add("danger", danger); + message.add("flag", flag); + + JsonObject player = new JsonObject(); + player.add("uuid", JsonUtil.createUuidObject(UUID.fromString("f17627d8-1a97-487b-92ea-c04f413394bd"))); + player.addProperty("name", "ItsNature"); + JsonObject target = new JsonObject(); + target.add("player", player); + message.add("target", target); + + message.addProperty("in_game_notification", true); + + JsonObject style = new JsonObject(); + style.addProperty("scale", 1.0F); + style.addProperty("animate_marker_on_hover", true); + style.addProperty("compact_mode", false); + style.addProperty("text_shadow", true); + style.addProperty("owner_suffix", "'s Marker"); + style.addProperty("owner_display", "MARKER_OWNER_DISPLAY_HEAD"); + style.addProperty("show_owner", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_coordinates", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_distance", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("show_description", "MARKER_DISPLAY_CONDITION_ALWAYS"); + style.addProperty("description_display", "MARKER_DESCRIPTION_DISPLAY_ICON"); + message.add("style", style); + + JsonPacketUtil.sendPacket(viewer, message); + } + + @Override + public void displayItemMarkerExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.DisplayMarkerMessage"); + message.addProperty("id", "wither-loot"); + message.add("location", JsonUtil.createLocationObject(viewer.getLocation())); + message.add("owner_id", JsonUtil.createUuidObject(viewer.getUniqueId())); + message.addProperty("owner_name", viewer.getName()); + + JsonObject flag = new JsonObject(); + flag.add("info", new JsonObject()); + message.add("flag", flag); + + JsonObject itemStack = new JsonObject(); + itemStack.addProperty("item_name", "minecraft:nether_star"); + JsonObject item = new JsonObject(); + item.add("item_stack", itemStack); + JsonObject target = new JsonObject(); + target.add("item", item); + message.add("target", target); + + message.addProperty("chat_notify", true); + + JsonObject style = new JsonObject(); + style.addProperty("scale", 1.0F); + style.addProperty("animate_marker_on_hover", true); + style.addProperty("compact_mode", false); + style.addProperty("text_shadow", true); + style.addProperty("owner_suffix", "'s Marker"); + style.addProperty("owner_display", "MARKER_OWNER_DISPLAY_HEAD"); + style.addProperty("show_owner", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_coordinates", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_distance", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("show_description", "MARKER_DISPLAY_CONDITION_ALWAYS"); + style.addProperty("description_display", "MARKER_DESCRIPTION_DISPLAY_ICON"); + message.add("style", style); + + JsonPacketUtil.sendPacket(viewer, message); + } + + @Override + public void displayEntityMarkerExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.DisplayMarkerMessage"); + message.addProperty("id", "tutorial-npc"); + message.add("location", JsonUtil.createLocationObject(viewer.getLocation())); + message.add("owner_id", JsonUtil.createUuidObject(UUID.randomUUID())); + message.addProperty("owner_name", "Tutorial NPC"); + + JsonObject flag = new JsonObject(); + flag.add("interest", new JsonObject()); + message.add("flag", flag); + + JsonObject entity = new JsonObject(); + entity.addProperty("entity_type", "minecraft:villager"); + JsonObject target = new JsonObject(); + target.add("entity", entity); + message.add("target", target); + + JsonObject style = new JsonObject(); + style.addProperty("scale", 1.3F); + style.addProperty("animate_marker_on_hover", true); + style.addProperty("compact_mode", false); + style.addProperty("text_shadow", true); + style.addProperty("owner_suffix", ""); + style.addProperty("owner_display", "MARKER_OWNER_DISPLAY_NAME"); + style.addProperty("show_owner", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("show_coordinates", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_distance", "MARKER_DISPLAY_CONDITION_NEVER"); + style.addProperty("show_description", "MARKER_DISPLAY_CONDITION_HOVER"); + style.addProperty("description_display", "MARKER_DESCRIPTION_DISPLAY_ICON"); + message.add("style", style); + + JsonPacketUtil.sendPacket(viewer, message); + } + + @Override + public void removeMarkersExample(Player viewer) { + List markerIds = Arrays.asList("loot-chest", "bounty", "wither-loot", "tutorial-npc"); + for (String id : markerIds) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.RemoveMarkerMessage"); + message.addProperty("id", id); + + JsonPacketUtil.sendPacket(viewer, message); + } + } + + @Override + public void resetMarkersExample(Player viewer) { + JsonObject message = new JsonObject(); + message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.marker.v1.ResetMarkersMessage"); + + JsonPacketUtil.sendPacket(viewer, 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 63fc5801..31617883 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 @@ -41,7 +41,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", "mod_setting", "nametag", "nick_hider", "notification", "pay_now", "packet_enrichment", + "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" ); diff --git a/example/bukkit/json/src/main/resources/plugin.yml b/example/bukkit/json/src/main/resources/plugin.yml index 12672845..5290ab7d 100644 --- a/example/bukkit/json/src/main/resources/plugin.yml +++ b/example/bukkit/json/src/main/resources/plugin.yml @@ -38,6 +38,8 @@ commands: description: "Inventory!" limb: description: "Limb!" + marker: + description: "Markers!" modsettings: description: "ModSettings!" nametag: 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 9112f059..94578ad4 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 @@ -38,6 +38,7 @@ import com.lunarclient.apollo.example.proto.module.GlowProtoExample; import com.lunarclient.apollo.example.proto.module.HologramProtoExample; import com.lunarclient.apollo.example.proto.module.LimbProtoExample; +import com.lunarclient.apollo.example.proto.module.MarkerProtoExample; import com.lunarclient.apollo.example.proto.module.ModSettingsProtoExample; import com.lunarclient.apollo.example.proto.module.NametagProtoExample; import com.lunarclient.apollo.example.proto.module.NickHiderProtoExample; @@ -82,6 +83,7 @@ public void registerModuleExamples() { this.setGlowExample(new GlowProtoExample()); this.setHologramExample(new HologramProtoExample()); this.setLimbExample(new LimbProtoExample()); + this.setMarkerExample(new MarkerProtoExample()); this.setModSettingsExample(new ModSettingsProtoExample()); this.setNametagExample(new NametagProtoExample()); this.setNickHiderExample(new NickHiderProtoExample()); diff --git a/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/MarkerProtoExample.java b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/MarkerProtoExample.java new file mode 100644 index 00000000..998a1d73 --- /dev/null +++ b/example/bukkit/proto/src/main/java/com/lunarclient/apollo/example/proto/module/MarkerProtoExample.java @@ -0,0 +1,210 @@ +/* + * 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.lunarclient.apollo.example.module.impl.MarkerExample; +import com.lunarclient.apollo.example.proto.util.ProtobufPacketUtil; +import com.lunarclient.apollo.example.proto.util.ProtobufUtil; +import com.lunarclient.apollo.marker.v1.BlockTarget; +import com.lunarclient.apollo.marker.v1.DangerMarker; +import com.lunarclient.apollo.marker.v1.DisplayMarkerMessage; +import com.lunarclient.apollo.marker.v1.EntityTarget; +import com.lunarclient.apollo.marker.v1.InfoMarker; +import com.lunarclient.apollo.marker.v1.InterestMarker; +import com.lunarclient.apollo.marker.v1.ItemTarget; +import com.lunarclient.apollo.marker.v1.MarkerDescriptionDisplay; +import com.lunarclient.apollo.marker.v1.MarkerDisplayCondition; +import com.lunarclient.apollo.marker.v1.MarkerFlag; +import com.lunarclient.apollo.marker.v1.MarkerOwnerDisplay; +import com.lunarclient.apollo.marker.v1.MarkerStyle; +import com.lunarclient.apollo.marker.v1.MarkerTarget; +import com.lunarclient.apollo.marker.v1.PlayerTarget; +import com.lunarclient.apollo.marker.v1.RemoveMarkerMessage; +import com.lunarclient.apollo.marker.v1.ResetMarkersMessage; +import java.awt.Color; +import java.time.Duration; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; +import org.bukkit.entity.Player; + +public class MarkerProtoExample extends MarkerExample { + + @Override + public void displayBlockMarkerExample(Player viewer) { + DisplayMarkerMessage message = DisplayMarkerMessage.newBuilder() + .setId("loot-chest") + .setLocation(ProtobufUtil.createLocationProto(viewer.getLocation())) + .setOwnerId(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .setOwnerName("") + .setFlag(MarkerFlag.newBuilder() + .setInterest(InterestMarker.getDefaultInstance()) + .build()) + .setTarget(MarkerTarget.newBuilder() + .setBlock(BlockTarget.newBuilder() + .setItemStack(ProtobufUtil.createItemStackIconProto("minecraft:chest", 0)) + .build()) + .build()) + .setDuration(ProtobufUtil.createDurationProto(Duration.ofSeconds(60))) + .setStyle(MarkerStyle.newBuilder() + .setScale(1.0F) + .setAnimateMarkerOnHover(true) + .setCompactMode(false) + .setTextShadow(true) + .setOwnerSuffix("'s Marker") + .setOwnerDisplay(MarkerOwnerDisplay.MARKER_OWNER_DISPLAY_HEAD) + .setShowOwner(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowCoordinates(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDistance(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setShowDescription(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_ALWAYS) + .setDescriptionDisplay(MarkerDescriptionDisplay.MARKER_DESCRIPTION_DISPLAY_ICON) + .build()) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } + + @Override + public void displayPlayerMarkerExample(Player viewer) { + DisplayMarkerMessage message = DisplayMarkerMessage.newBuilder() + .setId("bounty") + .setLocation(ProtobufUtil.createLocationProto(viewer.getLocation())) + .setOwnerId(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .setOwnerName(viewer.getName()) + .setFlag(MarkerFlag.newBuilder() + .setDanger(DangerMarker.newBuilder() + .setColor(ProtobufUtil.createColorProto(Color.RED)) + .build()) + .build()) + .setTarget(MarkerTarget.newBuilder() + .setPlayer(PlayerTarget.newBuilder() + .setUuid(ProtobufUtil.createUuidProto(UUID.fromString("f17627d8-1a97-487b-92ea-c04f413394bd"))) + .setName("ItsNature") + .build()) + .build()) + .setInGameNotification(true) + .setStyle(MarkerStyle.newBuilder() + .setScale(1.0F) + .setAnimateMarkerOnHover(true) + .setCompactMode(false) + .setTextShadow(true) + .setOwnerSuffix("'s Marker") + .setOwnerDisplay(MarkerOwnerDisplay.MARKER_OWNER_DISPLAY_HEAD) + .setShowOwner(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowCoordinates(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDistance(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setShowDescription(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_ALWAYS) + .setDescriptionDisplay(MarkerDescriptionDisplay.MARKER_DESCRIPTION_DISPLAY_ICON) + .build()) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } + + @Override + public void displayItemMarkerExample(Player viewer) { + DisplayMarkerMessage message = DisplayMarkerMessage.newBuilder() + .setId("wither-loot") + .setLocation(ProtobufUtil.createLocationProto(viewer.getLocation())) + .setOwnerId(ProtobufUtil.createUuidProto(viewer.getUniqueId())) + .setOwnerName(viewer.getName()) + .setFlag(MarkerFlag.newBuilder() + .setInfo(InfoMarker.getDefaultInstance()) + .build()) + .setTarget(MarkerTarget.newBuilder() + .setItem(ItemTarget.newBuilder() + .setItemStack(ProtobufUtil.createItemStackIconProto("minecraft:nether_star", 0)) + .build()) + .build()) + .setChatNotify(true) + .setStyle(MarkerStyle.newBuilder() + .setScale(1.0F) + .setAnimateMarkerOnHover(true) + .setCompactMode(false) + .setTextShadow(true) + .setOwnerSuffix("'s Marker") + .setOwnerDisplay(MarkerOwnerDisplay.MARKER_OWNER_DISPLAY_HEAD) + .setShowOwner(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowCoordinates(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDistance(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setShowDescription(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_ALWAYS) + .setDescriptionDisplay(MarkerDescriptionDisplay.MARKER_DESCRIPTION_DISPLAY_ICON) + .build()) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } + + @Override + public void displayEntityMarkerExample(Player viewer) { + DisplayMarkerMessage message = DisplayMarkerMessage.newBuilder() + .setId("tutorial-npc") + .setLocation(ProtobufUtil.createLocationProto(viewer.getLocation())) + .setOwnerId(ProtobufUtil.createUuidProto(UUID.randomUUID())) + .setOwnerName("Tutorial NPC") + .setFlag(MarkerFlag.newBuilder() + .setInterest(InterestMarker.getDefaultInstance()) + .build()) + .setTarget(MarkerTarget.newBuilder() + .setEntity(EntityTarget.newBuilder() + .setEntityType("minecraft:villager") + .build()) + .build()) + .setStyle(MarkerStyle.newBuilder() + .setScale(1.3F) + .setAnimateMarkerOnHover(true) + .setCompactMode(false) + .setTextShadow(true) + .setOwnerSuffix("") + .setOwnerDisplay(MarkerOwnerDisplay.MARKER_OWNER_DISPLAY_NAME) + .setShowOwner(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setShowCoordinates(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDistance(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_NEVER) + .setShowDescription(MarkerDisplayCondition.MARKER_DISPLAY_CONDITION_HOVER) + .setDescriptionDisplay(MarkerDescriptionDisplay.MARKER_DESCRIPTION_DISPLAY_ICON) + .build()) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } + + @Override + public void removeMarkersExample(Player viewer) { + List markerIds = Arrays.asList("loot-chest", "bounty", "wither-loot", "tutorial-npc"); + for (String id : markerIds) { + RemoveMarkerMessage message = RemoveMarkerMessage.newBuilder() + .setId(id) + .build(); + + ProtobufPacketUtil.sendPacket(viewer, message); + } + } + + @Override + public void resetMarkersExample(Player viewer) { + ResetMarkersMessage message = ResetMarkersMessage.getDefaultInstance(); + ProtobufPacketUtil.sendPacket(viewer, 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 b0ba4ac1..f8a0e17c 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 @@ -42,7 +42,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", "mod_setting", "nametag", "nick_hider", "notification", "pay_now", "packet_enrichment", + "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" ); diff --git a/example/bukkit/proto/src/main/resources/plugin.yml b/example/bukkit/proto/src/main/resources/plugin.yml index ef931e21..44fdb87e 100644 --- a/example/bukkit/proto/src/main/resources/plugin.yml +++ b/example/bukkit/proto/src/main/resources/plugin.yml @@ -38,6 +38,8 @@ commands: description: "Inventory!" limb: description: "Limb!" + marker: + description: "Markers!" modsettings: description: "ModSettings!" nametag: 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 220be9b1..6de2e988 100644 --- a/platform/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java +++ b/platform/bukkit/src/main/java/com/lunarclient/apollo/ApolloBukkitPlatform.java @@ -55,6 +55,8 @@ import com.lunarclient.apollo.module.inventory.InventoryModule; import com.lunarclient.apollo.module.limb.LimbModule; import com.lunarclient.apollo.module.limb.LimbModuleImpl; +import com.lunarclient.apollo.module.marker.MarkerModule; +import com.lunarclient.apollo.module.marker.MarkerModuleImpl; import com.lunarclient.apollo.module.modsetting.ModSettingModule; import com.lunarclient.apollo.module.modsettings.ModSettingModuleImpl; import com.lunarclient.apollo.module.nametag.NametagModule; @@ -150,6 +152,7 @@ public void onEnable() { .addModule(HologramModule.class, new HologramModuleImpl()) .addModule(InventoryModule.class) .addModule(LimbModule.class, new LimbModuleImpl()) + .addModule(MarkerModule.class, new MarkerModuleImpl()) .addModule(ModSettingModule.class, new ModSettingModuleImpl()) .addModule(NametagModule.class, new NametagModuleImpl()) .addModule(NickHiderModule.class, new NickHiderModuleImpl()) 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 76cad083..a5f50d27 100644 --- a/platform/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java +++ b/platform/bungee/src/main/java/com/lunarclient/apollo/ApolloBungeePlatform.java @@ -50,6 +50,8 @@ import com.lunarclient.apollo.module.hologram.HologramModuleImpl; import com.lunarclient.apollo.module.limb.LimbModule; import com.lunarclient.apollo.module.limb.LimbModuleImpl; +import com.lunarclient.apollo.module.marker.MarkerModule; +import com.lunarclient.apollo.module.marker.MarkerModuleImpl; import com.lunarclient.apollo.module.modsetting.ModSettingModule; import com.lunarclient.apollo.module.modsettings.ModSettingModuleImpl; import com.lunarclient.apollo.module.nametag.NametagModule; @@ -131,6 +133,7 @@ public void onEnable() { .addModule(EntityModule.class, new EntityModuleImpl()) .addModule(HologramModule.class, new HologramModuleImpl()) .addModule(LimbModule.class, new LimbModuleImpl()) + .addModule(MarkerModule.class, new MarkerModuleImpl()) .addModule(ModSettingModule.class, new ModSettingModuleImpl()) .addModule(NametagModule.class, new NametagModuleImpl()) .addModule(NotificationModule.class, new NotificationModuleImpl()) 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 ecf29b87..19a4878b 100644 --- a/platform/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java +++ b/platform/folia/src/main/java/com/lunarclient/apollo/ApolloFoliaPlatform.java @@ -52,6 +52,8 @@ import com.lunarclient.apollo.module.hologram.HologramModuleImpl; import com.lunarclient.apollo.module.limb.LimbModule; import com.lunarclient.apollo.module.limb.LimbModuleImpl; +import com.lunarclient.apollo.module.marker.MarkerModule; +import com.lunarclient.apollo.module.marker.MarkerModuleImpl; import com.lunarclient.apollo.module.modsetting.ModSettingModule; import com.lunarclient.apollo.module.modsettings.ModSettingModuleImpl; import com.lunarclient.apollo.module.nametag.NametagModule; @@ -138,6 +140,7 @@ public void onEnable() { .addModule(GlowModule.class, new GlowModuleImpl()) .addModule(HologramModule.class, new HologramModuleImpl()) .addModule(LimbModule.class, new LimbModuleImpl()) + .addModule(MarkerModule.class, new MarkerModuleImpl()) .addModule(ModSettingModule.class, new ModSettingModuleImpl()) .addModule(NametagModule.class, new NametagModuleImpl()) .addModule(NickHiderModule.class, new NickHiderModuleImpl()) 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 ceb47d1e..caf5d4b2 100644 --- a/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java +++ b/platform/minestom/src/main/java/com/lunarclient/apollo/ApolloMinestomPlatform.java @@ -54,6 +54,8 @@ import com.lunarclient.apollo.module.inventory.InventoryModule; import com.lunarclient.apollo.module.limb.LimbModule; import com.lunarclient.apollo.module.limb.LimbModuleImpl; +import com.lunarclient.apollo.module.marker.MarkerModule; +import com.lunarclient.apollo.module.marker.MarkerModuleImpl; import com.lunarclient.apollo.module.modsetting.ModSettingModule; import com.lunarclient.apollo.module.modsettings.ModSettingModuleImpl; import com.lunarclient.apollo.module.nametag.NametagModule; @@ -172,6 +174,7 @@ public static void init(ApolloMinestomProperties properties) { .addModule(HologramModule.class, new HologramModuleImpl()) .addModule(InventoryModule.class) .addModule(LimbModule.class, new LimbModuleImpl()) + .addModule(MarkerModule.class, new MarkerModuleImpl()) .addModule(ModSettingModule.class, new ModSettingModuleImpl()) .addModule(NametagModule.class, new NametagModuleImpl()) .addModule(NickHiderModule.class, new NickHiderModuleImpl()) 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 e9b04e67..e19a3b00 100644 --- a/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java +++ b/platform/velocity/src/main/java/com/lunarclient/apollo/ApolloVelocityPlatform.java @@ -50,6 +50,8 @@ import com.lunarclient.apollo.module.hologram.HologramModuleImpl; import com.lunarclient.apollo.module.limb.LimbModule; import com.lunarclient.apollo.module.limb.LimbModuleImpl; +import com.lunarclient.apollo.module.marker.MarkerModule; +import com.lunarclient.apollo.module.marker.MarkerModuleImpl; import com.lunarclient.apollo.module.modsetting.ModSettingModule; import com.lunarclient.apollo.module.modsettings.ModSettingModuleImpl; import com.lunarclient.apollo.module.nametag.NametagModule; @@ -198,6 +200,7 @@ public void onProxyInitialization(ProxyInitializeEvent event) { .addModule(EntityModule.class, new EntityModuleImpl()) .addModule(HologramModule.class, new HologramModuleImpl()) .addModule(LimbModule.class, new LimbModuleImpl()) + .addModule(MarkerModule.class, new MarkerModuleImpl()) .addModule(ModSettingModule.class, new ModSettingModuleImpl()) .addModule(NametagModule.class, new NametagModuleImpl()) .addModule(NotificationModule.class, new NotificationModuleImpl())