99import com .mojang .brigadier .exceptions .SimpleCommandExceptionType ;
1010import com .mojang .brigadier .suggestion .Suggestions ;
1111import com .mojang .brigadier .suggestion .SuggestionsBuilder ;
12- import dev .ryanhcode .sable .command .argument .SubLevelSelector ;
1312import dev .ryanhcode .sable .command .argument .SubLevelSelectorModifierType ;
1413import dev .ryanhcode .sable .command .argument .SubLevelSelectorType ;
14+ import dev .ryanhcode .sable .command .argument .SubLevelSuggestionProvider ;
15+ import dev .ryanhcode .sable .command .argument .selector .SubLevelTarget ;
16+ import dev .ryanhcode .sable .command .argument .selector .SubLevelTargetNone ;
17+ import dev .ryanhcode .sable .command .argument .selector .SubLevelTargetSelector ;
18+ import dev .ryanhcode .sable .command .argument .selector .SubLevelTargetUUID ;
1519import dev .ryanhcode .sable .sublevel .ServerSubLevel ;
20+ import dev .ryanhcode .sable .sublevel .SubLevel ;
1621import it .unimi .dsi .fastutil .Pair ;
1722import it .unimi .dsi .fastutil .objects .ObjectArrayList ;
1823import it .unimi .dsi .fastutil .objects .ObjectList ;
2429import org .jetbrains .annotations .NotNull ;
2530import org .jetbrains .annotations .Nullable ;
2631
27- import java .util .ArrayList ;
28- import java .util .Arrays ;
29- import java .util .Collection ;
30- import java .util .List ;
32+ import java .util .*;
3133import java .util .concurrent .CompletableFuture ;
3234import java .util .function .Function ;
3335
34- public class SubLevelArgumentType implements ArgumentType <SubLevelSelector > {
36+ public class SubLevelArgumentType implements ArgumentType <SubLevelTarget > {
3537
36- public static final Function <SuggestionsBuilder , CompletableFuture < Suggestions >> NO_SUGGESTIONS = SuggestionsBuilder :: buildFuture ;
37- private static final SimpleCommandExceptionType ERROR_SINGLE_SUB_LEVEL_REQUIRED =
38+ public static final Function <SuggestionsBuilder , SuggestionsBuilder > NO_SUGGESTIONS = b -> b ;
39+ public static final SimpleCommandExceptionType ERROR_SINGLE_SUB_LEVEL_REQUIRED =
3840 new SimpleCommandExceptionType (Component .translatable ("argument.sable.single_sub_level_required" ));
39- private static final SimpleCommandExceptionType ERROR_INVALID_SUBLEVEL =
40- new SimpleCommandExceptionType (Component .translatable ("argument.sable.sub_level.invalid " ));
41- private static final SimpleCommandExceptionType UNEXPECTED_END_OF_INPUT =
41+ public static final SimpleCommandExceptionType ERROR_INVALID_SELECTOR =
42+ new SimpleCommandExceptionType (Component .translatable ("argument.sable.invalid_selector " ));
43+ public static final SimpleCommandExceptionType ERROR_UNEXPECTED_END_OF_INPUT =
4244 new SimpleCommandExceptionType (Component .translatable ("argument.sable.unexpected_end_of_input" ));
45+ public static final SimpleCommandExceptionType ERROR_INVALID_UUID = new SimpleCommandExceptionType (Component .translatable ("argument.sable.invalid_uuid" ));
46+ public static final SimpleCommandExceptionType ERROR_CANNOT_FIND_SUB_LEVEL = new SimpleCommandExceptionType (Component .translatable ("argument.sable.cannot_find_sub_level" ));
4347 private static final String STATIC_WORLD = "static_world" ;
4448 private static final Collection <String > EXAMPLES = Arrays .stream (SubLevelSelectorType .values ())
4549 .map (type -> "@" + type .getChar ()).toList ();
46- private static Function <SuggestionsBuilder , CompletableFuture < Suggestions >> suggestions = NO_SUGGESTIONS ;
50+ private static Function <SuggestionsBuilder , SuggestionsBuilder > SELECTOR_SUGGESTIONS = NO_SUGGESTIONS ;
4751 private final boolean allowStaticLevel ;
4852 private final boolean allowMultiple ;
4953
@@ -53,11 +57,11 @@ public SubLevelArgumentType(final boolean allowStaticLevel, final boolean allowM
5357 }
5458
5559 public static Collection <ServerSubLevel > getSubLevels (final CommandContext <CommandSourceStack > ctx , final String name ) throws CommandSyntaxException {
56- return ctx .getArgument (name , SubLevelSelector .class ).getSubLevels (ctx .getSource ());
60+ return ctx .getArgument (name , SubLevelTarget .class ).getSubLevels (ctx .getSource ());
5761 }
5862
5963 public static ServerSubLevel getSingleSubLevel (final CommandContext <CommandSourceStack > ctx , final String name ) throws CommandSyntaxException {
60- final Collection <ServerSubLevel > subLevels = ctx .getArgument (name , SubLevelSelector .class ).getSubLevels (ctx .getSource ());
64+ final Collection <ServerSubLevel > subLevels = ctx .getArgument (name , SubLevelTarget .class ).getSubLevels (ctx .getSource ());
6165 if (subLevels .size () > 1 ) {
6266 throw ERROR_SINGLE_SUB_LEVEL_REQUIRED .create ();
6367 }
@@ -83,7 +87,7 @@ public static SubLevelArgumentType subLevelsOrLevel() {
8387
8488 private static @ NotNull List <Pair <SubLevelSelectorModifierType , SubLevelSelectorModifierType .Modifier >> parseSelectorArguments (final StringReader reader ) throws CommandSyntaxException {
8589 final List <Pair <SubLevelSelectorModifierType , SubLevelSelectorModifierType .Modifier >> modifiers = new ObjectArrayList <>();
86- setSuggestions (reader , "[" );
90+ setSelectorSuggestions (reader , "[" );
8791
8892 final List <Pair <String , @ Nullable Message >> permittedPreEntryToken = new ArrayList <>(SubLevelSelectorModifierType .getAllNamesWithTooltip ()
8993 .stream ().map (s -> Pair .of (s .first () + "=" , s .second ())).toList ());
@@ -93,28 +97,28 @@ public static SubLevelArgumentType subLevelsOrLevel() {
9397 if (reader .canRead () && reader .peek () == '[' ) {
9498 reader .skip ();
9599
96- setSuggestionsWithTooltip (reader , permittedPreEntryToken );
100+ setSelectorSuggestionsWithTooltip (reader , permittedPreEntryToken );
97101 while (reader .canRead () && reader .peek () != ']' ) {
98102 if (reader .peek () == ',' ) {
99103 reader .skip ();
100104 }
101- setSuggestionsWithTooltip (reader , permittedPreEntryToken );
105+ setSelectorSuggestionsWithTooltip (reader , permittedPreEntryToken );
102106
103107 final String propertyName = readUntilEndOrCharacter (reader , '=' );
104108
105109 if (!reader .canRead () || reader .peek () != '=' ) {
106- throw UNEXPECTED_END_OF_INPUT .createWithContext (reader );
110+ throw ERROR_UNEXPECTED_END_OF_INPUT .createWithContext (reader );
107111 }
108112 reader .skip ();
109113
110114 final SubLevelSelectorModifierType modifierType = SubLevelSelectorModifierType .getModifier (propertyName , reader );
111115 if (modifierType == null ) {
112- throw UNEXPECTED_END_OF_INPUT .createWithContext (reader );
116+ throw ERROR_UNEXPECTED_END_OF_INPUT .createWithContext (reader );
113117 }
114118 final SubLevelSelectorModifierType .Modifier modifier = modifierType .getParser ().parse (reader );
115119 modifiers .add (Pair .of (modifierType , modifier ));
116120
117- setSuggestionsWithTooltip (reader , permittedPreEntryToken );
121+ setSelectorSuggestionsWithTooltip (reader , permittedPreEntryToken );
118122 if (isFirstEntry ) {
119123 permittedPreEntryToken .add (Pair .of ("," , null ));
120124 isFirstEntry = false ;
@@ -124,32 +128,33 @@ public static SubLevelArgumentType subLevelsOrLevel() {
124128 if (reader .canRead () && reader .peek () == ']' ) {
125129 reader .skip ();
126130 } else {
127- throw UNEXPECTED_END_OF_INPUT .createWithContext (reader );
131+ throw ERROR_UNEXPECTED_END_OF_INPUT .createWithContext (reader );
128132 }
129133 }
130134
131135 return modifiers ;
132136 }
133137
134- public static void setSuggestions (final StringReader reader , final String ... suggested ) {
135- setSuggestions (reader , Arrays .asList (suggested ));
138+ public static void setSelectorSuggestions (final StringReader reader , final String ... suggested ) {
139+ setSelectorSuggestions (reader , Arrays .asList (suggested ));
136140 }
137141
138- public static void setSuggestions (final StringReader reader , final List <String > suggested ) {
139- setSuggestionsWithTooltip (reader , suggested .stream ().map (s -> Pair .of (s , (Message ) null )).toList ());
142+ public static void setSelectorSuggestions (final StringReader reader , final List <String > suggested ) {
143+ setSelectorSuggestionsWithTooltip (reader , suggested .stream ().map (s -> Pair .of (s , (Message ) null )).toList ());
140144 }
141145
142146 @ SafeVarargs
143- public static void setSuggestionsWithTooltip (final StringReader reader , final Pair <String , @ Nullable Message >... suggested ) {
144- setSuggestionsWithTooltip (reader , Arrays .asList (suggested ));
147+ public static void setSelectorSuggestionsWithTooltip (final StringReader reader , final Pair <String , @ Nullable Message >... suggested ) {
148+ setSelectorSuggestionsWithTooltip (reader , Arrays .asList (suggested ));
145149 }
146150
147- public static void setSuggestionsWithTooltip (final StringReader reader , final List <Pair <String , @ Nullable Message >> suggested ) {
151+ public static void setSelectorSuggestionsWithTooltip (final StringReader reader , final List <Pair <String , @ Nullable Message >> suggested ) {
148152 final int cursor = reader .getCursor ();
149- suggestions = builder -> {
153+ SELECTOR_SUGGESTIONS = builder -> {
150154 final SuggestionsBuilder nextSuggestion = builder .createOffset (cursor );
155+ final String input = builder .getInput ().substring (cursor );
151156 for (final Pair <String , @ Nullable Message > suggestion : suggested ) {
152- if (!suggestion .first ().startsWith (builder . getInput (). substring ( cursor ) )) {
157+ if (!suggestion .first ().startsWith (input )) {
153158 continue ;
154159 }
155160 if (suggestion .second () != null ) {
@@ -158,7 +163,7 @@ public static void setSuggestionsWithTooltip(final StringReader reader, final Li
158163 nextSuggestion .suggest (suggestion .first ());
159164 }
160165 }
161- return nextSuggestion . buildFuture () ;
166+ return nextSuggestion ;
162167 };
163168 }
164169
@@ -168,49 +173,54 @@ public static String readUntilEndOrCharacter(final StringReader reader, final ch
168173 builder .append (reader .read ());
169174 }
170175 if (builder .isEmpty ()) {
171- throw UNEXPECTED_END_OF_INPUT .create ();
176+ throw ERROR_UNEXPECTED_END_OF_INPUT .create ();
172177 }
173178 return builder .toString ();
174179 }
175180
176181 @ Override
177- public SubLevelSelector parse (final StringReader reader ) throws CommandSyntaxException {
182+ public SubLevelTarget parse (final StringReader reader ) throws CommandSyntaxException {
178183 final ObjectList <Pair <String , @ Nullable Message >> allowedSelectors = new ObjectArrayList <>();
179184 if (this .allowStaticLevel ) {
180185 allowedSelectors .add (Pair .of (STATIC_WORLD , Component .translatable ("argument.sable.body.static_world" )));
181186 }
182187 for (final SubLevelSelectorType selector : SubLevelSelectorType .values ()) {
183188 allowedSelectors .add (Pair .of ("@" + selector .getChar (), selector .getTooltip ()));
184189 }
185- setSuggestionsWithTooltip (reader , allowedSelectors );
190+ setSelectorSuggestionsWithTooltip (reader , allowedSelectors );
186191
187192 if (this .allowStaticLevel && reader .canRead (STATIC_WORLD .length ()) && reader .peek () == STATIC_WORLD .charAt (0 )) {
188193 final String staticWorld = reader .readString ();
189194
190195 if (!staticWorld .equals (STATIC_WORLD )) {
191- throw ERROR_INVALID_SUBLEVEL .create ();
196+ throw ERROR_INVALID_SELECTOR .create ();
192197 }
193198
194- return new SubLevelSelector ( null , new ObjectArrayList <>()) ;
199+ return SubLevelTargetNone . INSTANCE ;
195200 }
196201
197202 if (!reader .canRead ()) {
198- throw ERROR_INVALID_SUBLEVEL .create ();
203+ throw ERROR_INVALID_SELECTOR .create ();
199204 }
200205
201- final char firstChar = reader .read ();
206+ final char firstChar = reader .peek ();
202207
203- if (!reader .canRead () || firstChar != '@' ) {
204- throw ERROR_INVALID_SUBLEVEL .create ();
208+ if (firstChar == '@' ) {
209+ reader .skip ();
210+ return this .parseSelector (reader );
211+ } else {
212+ return this .parseUUID (reader );
205213 }
214+ }
206215
216+ private SubLevelTarget parseSelector (final StringReader reader ) throws CommandSyntaxException {
207217 if (!reader .canRead ()) {
208- throw ERROR_INVALID_SUBLEVEL .create ();
218+ throw ERROR_INVALID_SELECTOR .create ();
209219 }
210220
211221 final SubLevelSelectorType selectorType = SubLevelSelectorType .of (reader .read ());
212222 if (selectorType == null ) {
213- throw ERROR_INVALID_SUBLEVEL .create ();
223+ throw ERROR_INVALID_SELECTOR .create ();
214224 }
215225
216226 int maximumResults = Integer .MAX_VALUE ;
@@ -230,19 +240,41 @@ public SubLevelSelector parse(final StringReader reader) throws CommandSyntaxExc
230240 throw ERROR_SINGLE_SUB_LEVEL_REQUIRED .create ();
231241 }
232242
233- return new SubLevelSelector (selectorType , modifiers );
243+ return new SubLevelTargetSelector (selectorType , modifiers );
244+ }
245+
246+ private SubLevelTarget parseUUID (final StringReader reader ) throws CommandSyntaxException {
247+ final String s = reader .readString ();
248+ try {
249+ return new SubLevelTargetUUID (UUID .fromString (s ));
250+ } catch (final IllegalArgumentException e ) {
251+ throw ERROR_INVALID_UUID .createWithContext (reader );
252+ }
234253 }
235254
236255 @ Override
237- public <S > CompletableFuture <Suggestions > listSuggestions (final CommandContext <S > pContext , final SuggestionsBuilder builder ) {
256+ public <S > CompletableFuture <Suggestions > listSuggestions (final CommandContext <S > pContext , SuggestionsBuilder builder ) {
238257 final StringReader stringreader = new StringReader (builder .getInput ());
239- stringreader .setCursor (builder .getStart ());
240- suggestions = NO_SUGGESTIONS ;
258+ final int start = builder .getStart ();
259+ stringreader .setCursor (start );
260+ SELECTOR_SUGGESTIONS = NO_SUGGESTIONS ;
241261 try {
242262 this .parse (stringreader );
243263 } catch (final CommandSyntaxException ignored ) {
244264 }
245- return suggestions .apply (builder );
265+ builder = SELECTOR_SUGGESTIONS .apply (builder );
266+
267+ if (pContext .getSource () instanceof final SubLevelSuggestionProvider suggestionProvider ) {
268+ final SubLevel subLevel = suggestionProvider .getSelectedSubLevel ();
269+ if (subLevel != null ) {
270+ final String uuid = subLevel .getUniqueId ().toString ();
271+ final String input = builder .getInput ().substring (start );
272+ if (uuid .startsWith (input )) {
273+ builder .suggest (uuid );
274+ }
275+ }
276+ }
277+ return builder .buildFuture ();
246278 }
247279
248280 @ Override
0 commit comments