Skip to content

Commit 5868a14

Browse files
committed
Height Limit Module
1 parent 08b6bed commit 5868a14

27 files changed

Lines changed: 910 additions & 5 deletions

File tree

.github/workflows/deploy.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ jobs:
4141
fi
4242
4343
- name: Gradle Publish
44-
if: "${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/version/') }}"
44+
if: "${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/heads/version/') || github.ref == `refs/heads/feature/height-limit` }}"
4545
run: ./gradlew publish
4646

4747
- name: Gradle Release
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* This file is part of Apollo, licensed under the MIT License.
3+
*
4+
* Copyright (c) 2026 Moonsworth
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package com.lunarclient.apollo.module.heightlimit;
25+
26+
import lombok.Builder;
27+
import lombok.Getter;
28+
import net.kyori.adventure.text.Component;
29+
import org.jetbrains.annotations.Nullable;
30+
import org.jetbrains.annotations.Range;
31+
32+
/**
33+
* Represents a height limit which can be shown on the client.
34+
*
35+
* @since 1.2.9
36+
*/
37+
@Getter
38+
@Builder
39+
public final class HeightLimit {
40+
41+
/**
42+
* Returns the height limit {@link String} world name.
43+
*
44+
* @return the height limit world name
45+
* @since 1.2.9
46+
*/
47+
String world;
48+
49+
/**
50+
* Returns the height limit {@link Integer} Y level where block placement
51+
* is denied.
52+
*
53+
* <p>The highest buildable layer is {@code limit - 1}.</p>
54+
*
55+
* @return the height limit
56+
* @since 1.2.9
57+
*/
58+
@Range(from = 1, to = Integer.MAX_VALUE) int limit;
59+
60+
/**
61+
* Returns the height limit {@link Component} display name.
62+
*
63+
* <p>Shown on the client's height limit HUD.</p>
64+
*
65+
* @return the height limit display name
66+
* @since 1.2.9
67+
*/
68+
@Nullable Component displayName;
69+
70+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/*
2+
* This file is part of Apollo, licensed under the MIT License.
3+
*
4+
* Copyright (c) 2026 Moonsworth
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package com.lunarclient.apollo.module.heightlimit;
25+
26+
import com.lunarclient.apollo.module.ApolloModule;
27+
import com.lunarclient.apollo.module.ModuleDefinition;
28+
import com.lunarclient.apollo.option.ListOption;
29+
import com.lunarclient.apollo.option.Option;
30+
import com.lunarclient.apollo.recipients.Recipients;
31+
import io.leangen.geantyref.TypeToken;
32+
import java.util.ArrayList;
33+
import java.util.List;
34+
import org.jetbrains.annotations.ApiStatus;
35+
36+
/**
37+
* Represents the height limit module.
38+
*
39+
* <p>Sets the build-height limit shown by the clients Height Limit mod
40+
* (block overlay and HUD display). The client resolves the active limit
41+
* against the world the player is currently in.</p>
42+
*
43+
* @since 1.2.9
44+
*/
45+
@ApiStatus.NonExtendable
46+
@ModuleDefinition(id = "height_limit", name = "Height Limit")
47+
public abstract class HeightLimitModule extends ApolloModule {
48+
49+
/**
50+
* Returns the default list of height limits to send to the player.
51+
*
52+
* @since 1.2.9
53+
*/
54+
public static final ListOption<HeightLimit> DEFAULT_HEIGHT_LIMITS = Option.<HeightLimit>list()
55+
.comment("Sets the default height limits to send to the player.")
56+
.node("default-height-limits").type(new TypeToken<List<HeightLimit>>() {})
57+
.defaultValue(new ArrayList<>())
58+
.build();
59+
60+
protected HeightLimitModule() {
61+
this.registerOptions(
62+
ApolloModule.ENABLE_OPTION_OFF,
63+
HeightLimitModule.DEFAULT_HEIGHT_LIMITS
64+
);
65+
}
66+
67+
/**
68+
* Overrides the {@link HeightLimit} for the {@link Recipients}.
69+
*
70+
* <p>Sending a height limit for an already-known world replaces
71+
* that worlds entry.</p>
72+
*
73+
* @param recipients the recipients that are receiving the packet
74+
* @param heightLimit the height limit
75+
* @since 1.2.9
76+
*/
77+
public abstract void overrideHeightLimit(Recipients recipients, HeightLimit heightLimit);
78+
79+
/**
80+
* Removes the {@link HeightLimit} from the {@link Recipients}.
81+
*
82+
* @param recipients the recipients that are receiving the packet
83+
* @param world the world name
84+
* @since 1.2.9
85+
*/
86+
public abstract void removeHeightLimit(Recipients recipients, String world);
87+
88+
/**
89+
* Removes the {@link HeightLimit} from the {@link Recipients}.
90+
*
91+
* @param recipients the recipients that are receiving the packet
92+
* @param heightLimit the height limit
93+
* @since 1.2.9
94+
*/
95+
public abstract void removeHeightLimit(Recipients recipients, HeightLimit heightLimit);
96+
97+
/**
98+
* Resets all {@link HeightLimit}s for the {@link Recipients}.
99+
*
100+
* @param recipients the recipients that are receiving the packet
101+
* @since 1.2.9
102+
*/
103+
public abstract void resetHeightLimits(Recipients recipients);
104+
105+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* This file is part of Apollo, licensed under the MIT License.
3+
*
4+
* Copyright (c) 2026 Moonsworth
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in all
14+
* copies or substantial portions of the Software.
15+
*
16+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22+
* SOFTWARE.
23+
*/
24+
package com.lunarclient.apollo.module.heightlimit;
25+
26+
import com.lunarclient.apollo.ApolloManager;
27+
import com.lunarclient.apollo.common.ApolloComponent;
28+
import com.lunarclient.apollo.event.player.ApolloRegisterPlayerEvent;
29+
import com.lunarclient.apollo.heightlimit.v1.OverrideHeightLimitMessage;
30+
import com.lunarclient.apollo.heightlimit.v1.RemoveHeightLimitMessage;
31+
import com.lunarclient.apollo.heightlimit.v1.ResetHeightLimitsMessage;
32+
import com.lunarclient.apollo.option.config.Serializer;
33+
import com.lunarclient.apollo.player.ApolloPlayer;
34+
import com.lunarclient.apollo.recipients.Recipients;
35+
import java.lang.reflect.Type;
36+
import java.util.Arrays;
37+
import java.util.List;
38+
import lombok.NonNull;
39+
import net.kyori.adventure.text.Component;
40+
import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer;
41+
import org.checkerframework.checker.nullness.qual.Nullable;
42+
import org.spongepowered.configurate.ConfigurationNode;
43+
import org.spongepowered.configurate.serialize.SerializationException;
44+
import org.spongepowered.configurate.serialize.TypeSerializer;
45+
46+
import static com.lunarclient.apollo.util.Ranges.checkStrictlyPositive;
47+
48+
/**
49+
* Provides the height limit module.
50+
*
51+
* @since 1.2.9
52+
*/
53+
public final class HeightLimitModuleImpl extends HeightLimitModule implements Serializer {
54+
55+
/**
56+
* Creates a new instance of {@link HeightLimitModuleImpl}.
57+
*
58+
* @since 1.2.9
59+
*/
60+
public HeightLimitModuleImpl() {
61+
super();
62+
this.serializer(HeightLimit.class, new HeightLimitSerializer());
63+
this.handle(ApolloRegisterPlayerEvent.class, this::onPlayerRegister);
64+
}
65+
66+
@Override
67+
public void overrideHeightLimit(@NonNull Recipients recipients, @NonNull HeightLimit heightLimit) {
68+
OverrideHeightLimitMessage.Builder builder = OverrideHeightLimitMessage.newBuilder()
69+
.setWorld(heightLimit.getWorld())
70+
.setLimit(checkStrictlyPositive(heightLimit.getLimit(), "HeightLimit#limit"));
71+
72+
Component displayName = heightLimit.getDisplayName();
73+
if (displayName != null) {
74+
builder.setDisplayNameAdventureJsonLines(ApolloComponent.toJson(displayName));
75+
}
76+
77+
OverrideHeightLimitMessage message = builder.build();
78+
ApolloManager.getNetworkManager().sendPacket(recipients, message);
79+
}
80+
81+
@Override
82+
public void removeHeightLimit(@NonNull Recipients recipients, @NonNull String world) {
83+
RemoveHeightLimitMessage message = RemoveHeightLimitMessage.newBuilder()
84+
.setWorld(world)
85+
.build();
86+
87+
ApolloManager.getNetworkManager().sendPacket(recipients, message);
88+
}
89+
90+
@Override
91+
public void removeHeightLimit(@NonNull Recipients recipients, @NonNull HeightLimit heightLimit) {
92+
this.removeHeightLimit(recipients, heightLimit.getWorld());
93+
}
94+
95+
@Override
96+
public void resetHeightLimits(@NonNull Recipients recipients) {
97+
ResetHeightLimitsMessage message = ResetHeightLimitsMessage.getDefaultInstance();
98+
ApolloManager.getNetworkManager().sendPacket(recipients, message);
99+
}
100+
101+
private void onPlayerRegister(ApolloRegisterPlayerEvent event) {
102+
ApolloPlayer player = event.getPlayer();
103+
List<HeightLimit> heightLimits = this.getOptions().get(player, HeightLimitModule.DEFAULT_HEIGHT_LIMITS);
104+
105+
if (heightLimits != null) {
106+
for (HeightLimit heightLimit : heightLimits) {
107+
this.overrideHeightLimit(player, heightLimit);
108+
}
109+
}
110+
}
111+
112+
private static final class HeightLimitSerializer implements TypeSerializer<HeightLimit> {
113+
114+
@Override
115+
public HeightLimit deserialize(Type type, ConfigurationNode node) throws SerializationException {
116+
HeightLimit.HeightLimitBuilder builder = HeightLimit.builder()
117+
.world(this.virtualNode(node, "world").getString())
118+
.limit(this.virtualNode(node, "limit").getInt());
119+
120+
String displayName = node.node("display-name").getString();
121+
if (displayName != null) {
122+
builder.displayName(ApolloComponent.fromLegacy(displayName));
123+
}
124+
125+
return builder.build();
126+
}
127+
128+
@Override
129+
public void serialize(Type type, @Nullable HeightLimit heightLimit, ConfigurationNode node) throws SerializationException {
130+
if (heightLimit == null) {
131+
node.raw(null);
132+
return;
133+
}
134+
135+
node.node("world").set(heightLimit.getWorld());
136+
node.node("limit").set(heightLimit.getLimit());
137+
138+
Component displayName = heightLimit.getDisplayName();
139+
if (displayName != null) {
140+
node.node("display-name").set(LegacyComponentSerializer.legacyAmpersand().serialize(displayName));
141+
}
142+
}
143+
144+
private ConfigurationNode virtualNode(ConfigurationNode source, Object... path) throws SerializationException {
145+
if (!source.hasChild(path)) {
146+
throw new SerializationException("Required field " + Arrays.toString(path) + " not found!");
147+
}
148+
149+
return source.node(path);
150+
}
151+
}
152+
153+
}

docs/developers/lightweight/protobuf.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Available fields for each message, including their types, are available on the B
2626
<dependency>
2727
<groupId>com.lunarclient</groupId>
2828
<artifactId>apollo-protos</artifactId>
29-
<version>0.2.0</version>
29+
<version>0.2.1</version>
3030
</dependency>
3131
</dependencies>
3232
```
@@ -41,7 +41,7 @@ Available fields for each message, including their types, are available on the B
4141
}
4242
4343
dependencies {
44-
api 'com.lunarclient:apollo-protos:0.2.0'
44+
api 'com.lunarclient:apollo-protos:0.2.1'
4545
}
4646
```
4747
</Tab>
@@ -55,7 +55,7 @@ Available fields for each message, including their types, are available on the B
5555
}
5656

5757
dependencies {
58-
api("com.lunarclient:apollo-protos:0.2.0")
58+
api("com.lunarclient:apollo-protos:0.2.1")
5959
}
6060
```
6161
</Tab>

docs/developers/modules.mdx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@ These modules are available to all servers using Apollo and do not require any p
1616
🔗 [Entity](/apollo/developers/modules/entity)<br/>
1717
🔗 [Glint](/apollo/developers/modules/glint)<br/>
1818
🔗 [Glow](/apollo/developers/modules/glow)<br/>
19+
🔗 [Height Limit](/apollo/developers/modules/heightlimit)<br/>
1920
🔗 [Hologram](/apollo/developers/modules/hologram)<br/>
2021
🔗 [Inventory](/apollo/developers/modules/inventory)<br/>
2122
🔗 [Limb](/apollo/developers/modules/limb)<br/>
23+
🔗 [Marker](/apollo/developers/modules/marker)<br/>
2224
🔗 [Mod Setting](/apollo/developers/modules/modsetting)<br/>
2325
🔗 [Nametag](/apollo/developers/modules/nametag)<br/>
2426
🔗 [Nick Hider](/apollo/developers/modules/nickhider)<br/>

docs/developers/modules/_meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"entity": "Entity",
1010
"glint": "Glint",
1111
"glow": "Glow",
12+
"heightlimit": "Height Limit",
1213
"hologram": "Hologram",
1314
"inventory": "Inventory",
1415
"limb": "Limb",

0 commit comments

Comments
 (0)