Skip to content

Commit f0b4f69

Browse files
Fully use ability namespaces and api changes
1 parent 09dc1aa commit f0b4f69

File tree

130 files changed

+796
-732
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+796
-732
lines changed

api/src/main/java/me/moros/bending/api/ability/AbilityDescription.java

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,50 +26,50 @@
2626
import java.util.Locale;
2727
import java.util.Objects;
2828
import java.util.function.Function;
29+
import java.util.function.UnaryOperator;
2930

3031
import me.moros.bending.api.ability.element.Element;
32+
import me.moros.bending.api.util.KeyUtil;
3133
import net.kyori.adventure.key.Key;
3234
import net.kyori.adventure.key.Keyed;
3335
import net.kyori.adventure.text.Component;
3436
import net.kyori.adventure.text.TextComponent;
3537
import net.kyori.adventure.text.event.ClickEvent;
3638
import net.kyori.adventure.translation.Translatable;
37-
import org.checkerframework.checker.nullness.qual.NonNull;
3839
import org.checkerframework.checker.nullness.qual.Nullable;
3940

4041
/**
4142
* AbilityDescription is immutable and thread-safe.
4243
* Assume that all collections returning AbilityDescription are also immutable
4344
*/
4445
public sealed class AbilityDescription implements Keyed, Translatable permits AbilityDescription.Sequence {
45-
public static final String NAMESPACE = "bending.ability";
46-
4746
private final Key key;
4847
private final String name;
49-
private final Function<AbilityDescription, ? extends Ability> constructor;
5048
private final Element element;
49+
private final Component displayName;
50+
private final Function<AbilityDescription, ? extends Ability> constructor;
5151
private final EnumSet<Activation> activations;
5252
private final Collection<String> requiredPermissions;
53-
private final Component displayName;
5453
private final boolean canBind;
5554
private final boolean hidden;
5655
private final boolean bypassCooldown;
5756
private final int hashcode;
5857

5958
private AbilityDescription(Builder builder) {
59+
key = builder.key;
6060
name = builder.name;
61-
constructor = builder.constructor;
6261
element = builder.element;
62+
displayName = Component.text(name, element.color());
63+
constructor = builder.constructor;
6364
activations = builder.activations;
6465
requiredPermissions = List.copyOf(builder.requiredPermissions);
6566
canBind = builder.canBind && !isActivatedBy(Activation.SEQUENCE);
6667
hidden = builder.hidden;
6768
bypassCooldown = builder.bypassCooldown;
68-
displayName = Component.text(name, element.color());
69-
hashcode = Objects.hash(name, element, activations);
70-
key = Key.key(NAMESPACE, name.toLowerCase(Locale.ROOT));
69+
hashcode = Objects.hash(key, element, activations);
7170
}
7271

72+
@Deprecated(forRemoval = true)
7373
public String name() {
7474
return name;
7575
}
@@ -106,28 +106,32 @@ public Collection<String> permissions() {
106106
return requiredPermissions;
107107
}
108108

109+
@Deprecated(forRemoval = true)
109110
public Component meta() {
110-
return displayName().clickEvent(ClickEvent.runCommand("/bending help " + name()));
111+
return displayName().clickEvent(ClickEvent.runCommand("/bending help " + key().asString()));
111112
}
112113

113114
@Override
114-
public @NonNull Key key() {
115+
public Key key() {
115116
return key;
116117
}
117118

118119
@Override
119-
public @NonNull String translationKey() {
120-
return NAMESPACE + "." + key().value();
120+
public String translationKey() {
121+
return key().namespace() + ".ability." + key().value();
121122
}
122123

124+
@Deprecated(forRemoval = true)
123125
public String descriptionKey() {
124126
return translationKey() + ".description";
125127
}
126128

129+
@Deprecated(forRemoval = true)
127130
public String instructionsKey() {
128131
return translationKey() + ".instructions";
129132
}
130133

134+
@Deprecated(forRemoval = true)
131135
public String deathKey() {
132136
return translationKey() + ".death";
133137
}
@@ -141,7 +145,7 @@ public boolean equals(Object obj) {
141145
return false;
142146
}
143147
AbilityDescription other = (AbilityDescription) obj;
144-
return name.equals(other.name) && element == other.element && activations.equals(other.activations);
148+
return key.equals(other.key) && element == other.element && activations.equals(other.activations);
145149
}
146150

147151
@Override
@@ -150,18 +154,29 @@ public int hashCode() {
150154
}
151155

152156
public static <T extends Ability> Builder builder(String name, Function<AbilityDescription, T> constructor) {
157+
return builder(KeyUtil.BENDING_NAMESPACE, name, constructor);
158+
}
159+
160+
public static <T extends Ability> Builder builder(String namespace, String name, Function<AbilityDescription, T> constructor) {
161+
Objects.requireNonNull(namespace);
153162
Objects.requireNonNull(name);
154163
Objects.requireNonNull(constructor);
155-
if (name.isEmpty()) {
156-
throw new IllegalArgumentException("Ability name cannot be empty!");
164+
if (namespace.isEmpty()) {
165+
namespace = KeyUtil.BENDING_NAMESPACE;
166+
}
167+
boolean validName = name.chars().allMatch(c -> (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
168+
if (name.isEmpty() || !validName) {
169+
throw new IllegalArgumentException("Name must be an alphabetical non-empty string!");
157170
}
158-
return new Builder(name, constructor);
171+
return new Builder(namespace, name, constructor);
159172
}
160173

161174
/**
162175
* Immutable and thread-safe representation of a sequence
163176
*/
164177
public static final class Sequence extends AbilityDescription {
178+
public static final int MAX_STEPS = 16;
179+
165180
private final List<SequenceStep> steps;
166181
private Component instructions;
167182

@@ -204,11 +219,11 @@ private Component generateInstructions() {
204219
// Check if the next instruction is to release sneak.
205220
SequenceStep next = steps.get(i + 1);
206221
if (desc.equals(next.ability()) && next.activation() == Activation.SNEAK_RELEASE) {
207-
key = Activation.NAMESPACE + ".sneak-tap";
222+
key = "bending.activation.sneak-tap";
208223
i++;
209224
}
210225
}
211-
builder.append(Component.text(desc.name())).append(Component.text(" ("))
226+
builder.append(desc.displayName()).append(Component.text(" ("))
212227
.append(Component.translatable(key)).append(Component.text(")"));
213228
}
214229
return builder.build();
@@ -241,19 +256,21 @@ public boolean matches(List<SequenceStep> otherSteps) {
241256
* Builder to create {@link AbilityDescription}.
242257
*/
243258
public static final class Builder {
259+
private final Key key;
244260
private final String name;
245-
private final Function<AbilityDescription, ? extends Ability> constructor;
246261
private Element element;
262+
private final Function<AbilityDescription, ? extends Ability> constructor;
247263
private EnumSet<Activation> activations;
248264
private Collection<String> requiredPermissions;
249265
private boolean canBind = true;
250266
private boolean hidden = false;
251267
private boolean bypassCooldown = false;
252268

253-
private <T extends Ability> Builder(String name, Function<AbilityDescription, T> constructor) {
269+
private <T extends Ability> Builder(String namespace, String name, Function<AbilityDescription, T> constructor) {
270+
this.key = Key.key(namespace, name.toLowerCase(Locale.ROOT));
254271
this.name = name;
255272
this.constructor = constructor;
256-
this.requiredPermissions = List.of(AbilityDescription.NAMESPACE + "." + name);
273+
this.requiredPermissions = List.of(defaultPermission());
257274
}
258275

259276
public Builder element(Element element) {
@@ -273,7 +290,7 @@ public Builder activation(Activation method, Activation @Nullable ... methods) {
273290

274291
public Builder require(String @Nullable ... permissions) {
275292
Collection<String> c = new ArrayList<>();
276-
c.add(AbilityDescription.NAMESPACE + "." + name);
293+
c.add(defaultPermission());
277294
if (permissions != null) {
278295
c.addAll(List.of(permissions));
279296
}
@@ -304,6 +321,19 @@ public AbilityDescription build() {
304321
return new AbilityDescription(this);
305322
}
306323

324+
public Sequence buildSequence(UnaryOperator<SequenceBuilder> function) {
325+
validate();
326+
if (!activations.contains(Activation.SEQUENCE)) {
327+
throw new IllegalStateException("Ability must be activated by sequence");
328+
}
329+
List<SequenceStep> sequenceSteps = function.apply(new SequenceBuilder()).validateAndBuild();
330+
return new Sequence(this, sequenceSteps);
331+
}
332+
333+
/**
334+
* @deprecated use {@link #buildSequence(UnaryOperator)} instead
335+
*/
336+
@Deprecated(forRemoval = true)
307337
public Sequence buildSequence(SequenceStep step1, SequenceStep step2, SequenceStep @Nullable ... steps) {
308338
validate();
309339
if (!activations.contains(Activation.SEQUENCE)) {
@@ -325,5 +355,9 @@ private void validate() {
325355
throw new IllegalStateException("Activation methods cannot be empty");
326356
}
327357
}
358+
359+
private String defaultPermission() {
360+
return "bending.ability." + key.value();
361+
}
328362
}
329363
}

api/src/main/java/me/moros/bending/api/ability/Activation.java

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,14 @@
1919

2020
package me.moros.bending.api.ability;
2121

22+
import me.moros.bending.api.util.KeyUtil;
2223
import net.kyori.adventure.key.Key;
23-
import net.kyori.adventure.key.Keyed;
2424
import net.kyori.adventure.translation.Translatable;
25-
import org.checkerframework.checker.nullness.qual.NonNull;
2625

2726
/**
2827
* Represents a type of ability activation.
2928
*/
30-
public enum Activation implements Keyed, Translatable {
29+
public enum Activation implements Translatable {
3130
/**
3231
* Passive abilities are always active.
3332
*/
@@ -68,18 +67,11 @@ public enum Activation implements Keyed, Translatable {
6867
private final Key key;
6968

7069
Activation(String value) {
71-
this.key = Key.key(NAMESPACE, value);
70+
this.key = KeyUtil.simple("activation." + value);
7271
}
7372

7473
@Override
75-
public @NonNull Key key() {
76-
return key;
74+
public String translationKey() {
75+
return KeyUtil.concat(key);
7776
}
78-
79-
@Override
80-
public @NonNull String translationKey() {
81-
return NAMESPACE + "." + key().value();
82-
}
83-
84-
public static final String NAMESPACE = "bending.activation";
8577
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright 2020-2024 Moros
3+
*
4+
* This file is part of Bending.
5+
*
6+
* Bending is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU Affero General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* Bending is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU Affero General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU Affero General Public License
17+
* along with Bending. If not, see <https://www.gnu.org/licenses/>.
18+
*/
19+
20+
package me.moros.bending.api.ability;
21+
22+
import java.util.ArrayList;
23+
import java.util.List;
24+
import java.util.Objects;
25+
26+
import me.moros.bending.api.ability.AbilityDescription.Sequence;
27+
import org.checkerframework.checker.nullness.qual.Nullable;
28+
29+
/**
30+
* Utility to link multiple {@link SequenceStep}.
31+
*/
32+
public final class SequenceBuilder {
33+
private final List<SequenceStep> steps;
34+
35+
SequenceBuilder() {
36+
this.steps = new ArrayList<>();
37+
}
38+
39+
public SequenceBuilder add(AbilityDescription ability, Activation activation) {
40+
Objects.requireNonNull(ability);
41+
Objects.requireNonNull(activation);
42+
if (steps.size() > Sequence.MAX_STEPS) {
43+
throw new IllegalStateException("Cannot add more than %d steps!".formatted(Sequence.MAX_STEPS));
44+
}
45+
if (!ability.canBind()) {
46+
throw new IllegalArgumentException("%s cannot be used as a sequence activation step!".formatted(ability.key().asString()));
47+
}
48+
if (activation == Activation.PASSIVE || activation == Activation.SEQUENCE) {
49+
throw new IllegalArgumentException("%s cannot be used for sequence activation!".formatted(activation.name()));
50+
}
51+
this.steps.add(SequenceStep.of(ability, activation));
52+
return this;
53+
}
54+
55+
public SequenceBuilder add(AbilityDescription ability, Activation activation, Activation @Nullable ... activations) {
56+
add(ability, activation);
57+
if (activations != null) {
58+
for (Activation temp : activations) {
59+
add(ability, temp);
60+
}
61+
}
62+
return this;
63+
}
64+
65+
List<SequenceStep> validateAndBuild() {
66+
if (steps.size() < 2) {
67+
throw new IllegalStateException("Sequences require at least 2 activation steps!");
68+
}
69+
return List.copyOf(steps);
70+
}
71+
}

api/src/main/java/me/moros/bending/api/ability/SequenceStep.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,16 @@
2323
* Pair representation of {@link AbilityDescription} and {@link Activation}.
2424
*/
2525
public record SequenceStep(AbilityDescription ability, Activation activation) {
26+
/**
27+
* @deprecated use {@link #of(AbilityDescription, Activation)} instead
28+
*/
29+
@Deprecated(forRemoval = true)
30+
public SequenceStep(AbilityDescription ability, Activation activation) {
31+
this.ability = ability;
32+
this.activation = activation;
33+
}
34+
35+
public static SequenceStep of(AbilityDescription ability, Activation activation) {
36+
return new SequenceStep(ability, activation);
37+
}
2638
}

api/src/main/java/me/moros/bending/api/ability/element/Element.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,12 @@
2323
import java.util.Locale;
2424

2525
import me.moros.bending.api.util.ColorPalette;
26+
import me.moros.bending.api.util.KeyUtil;
2627
import net.kyori.adventure.key.Key;
2728
import net.kyori.adventure.key.Keyed;
2829
import net.kyori.adventure.text.Component;
2930
import net.kyori.adventure.text.format.TextColor;
3031
import net.kyori.adventure.translation.Translatable;
31-
import org.checkerframework.checker.nullness.qual.NonNull;
3232
import org.checkerframework.checker.nullness.qual.Nullable;
3333

3434
/**
@@ -47,7 +47,7 @@ public enum Element implements Keyed, Translatable {
4747
Element(String elementName, TextColor color) {
4848
this.elementName = elementName;
4949
this.color = color;
50-
this.key = Key.key(NAMESPACE, elementName.toLowerCase(Locale.ROOT));
50+
this.key = KeyUtil.simple("element." + elementName.toLowerCase(Locale.ROOT));
5151
}
5252

5353
@Override
@@ -56,13 +56,13 @@ public String toString() {
5656
}
5757

5858
@Override
59-
public @NonNull Key key() {
59+
public Key key() {
6060
return key;
6161
}
6262

6363
@Override
64-
public @NonNull String translationKey() {
65-
return NAMESPACE + "." + key().value();
64+
public String translationKey() {
65+
return KeyUtil.concat(key);
6666
}
6767

6868
/**
@@ -106,7 +106,6 @@ public TextColor color() {
106106
return null;
107107
}
108108

109-
public static final String NAMESPACE = "bending.element";
110109
public static final List<Element> VALUES = List.of(values());
111110
public static final List<String> NAMES = List.of("Air", "Water", "Earth", "Fire");
112111
}

0 commit comments

Comments
 (0)