Skip to content

Commit 90473bd

Browse files
committed
More command improvements
1 parent 0535a29 commit 90473bd

File tree

3 files changed

+245
-29
lines changed

3 files changed

+245
-29
lines changed

BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/AbstractSuggestionProvider.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,15 @@
2626

2727
import java.util.Collection;
2828
import java.util.concurrent.CompletableFuture;
29-
import java.util.regex.Pattern;
3029

30+
import com.mojang.brigadier.arguments.StringArgumentType;
3131
import com.mojang.brigadier.context.CommandContext;
3232
import com.mojang.brigadier.exceptions.CommandSyntaxException;
3333
import com.mojang.brigadier.suggestion.SuggestionProvider;
3434
import com.mojang.brigadier.suggestion.Suggestions;
3535
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
3636

3737
public abstract class AbstractSuggestionProvider<S> implements SuggestionProvider<S> {
38-
39-
private static final Pattern ESCAPE_PATTERN = Pattern.compile("[^a-zA-Z0-9_-]");
4038

4139
@Override
4240
public CompletableFuture<Suggestions> getSuggestions(CommandContext<S> context, SuggestionsBuilder builder) throws CommandSyntaxException {
@@ -45,12 +43,8 @@ public CompletableFuture<Suggestions> getSuggestions(CommandContext<S> context,
4543

4644
String remaining = builder.getRemaining().toLowerCase();
4745
for (String str : possibleValues) {
48-
if (ESCAPE_PATTERN.matcher(str).find() && str.indexOf('"') == -1) {
49-
str = "\"" + str + "\"";
50-
}
51-
5246
if (str.toLowerCase().startsWith(remaining)) {
53-
builder.suggest(str);
47+
builder.suggest(str = StringArgumentType.escapeIfRequired(str));
5448
}
5549
}
5650

BlueMapCommon/src/main/java/de/bluecolored/bluemap/common/plugin/commands/Commands.java

Lines changed: 152 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@
4545
import com.mojang.brigadier.exceptions.CommandSyntaxException;
4646
import com.mojang.brigadier.tree.LiteralCommandNode;
4747

48+
import de.bluecolored.bluemap.api.BlueMapAPI;
49+
import de.bluecolored.bluemap.api.BlueMapMap;
50+
import de.bluecolored.bluemap.api.marker.MarkerAPI;
51+
import de.bluecolored.bluemap.api.marker.MarkerSet;
52+
import de.bluecolored.bluemap.api.marker.POIMarker;
4853
import de.bluecolored.bluemap.common.MapType;
4954
import de.bluecolored.bluemap.common.RenderTask;
5055
import de.bluecolored.bluemap.common.plugin.Plugin;
@@ -59,6 +64,8 @@
5964
import de.bluecolored.bluemap.core.world.World;
6065

6166
public class Commands<S> {
67+
68+
public static final String DEFAULT_MARKER_SET_ID = "markers";
6269

6370
private final Plugin plugin;
6471
private final CommandDispatcher<S> dispatcher;
@@ -99,11 +106,7 @@ public void init() {
99106
.then(argument("x", DoubleArgumentType.doubleArg())
100107
.then(argument("y", DoubleArgumentType.doubleArg())
101108
.then(argument("z", DoubleArgumentType.doubleArg())
102-
.executes(this::debugCommand)
103-
)
104-
)
105-
)
106-
)
109+
.executes(this::debugCommand)))))
107110
.build();
108111

109112
LiteralCommandNode<S> pauseCommand =
@@ -124,45 +127,34 @@ public void init() {
124127
.executes(this::renderCommand) // /bluemap render
125128

126129
.then(argument("radius", IntegerArgumentType.integer())
127-
.executes(this::renderCommand) // /bluemap render <radius>
128-
)
130+
.executes(this::renderCommand)) // /bluemap render <radius>
129131

130132
.then(argument("x", DoubleArgumentType.doubleArg())
131133
.then(argument("z", DoubleArgumentType.doubleArg())
132134
.then(argument("radius", IntegerArgumentType.integer())
133-
.executes(this::renderCommand) // /bluemap render <x> <z> <radius>
134-
)
135-
)
136-
)
135+
.executes(this::renderCommand)))) // /bluemap render <x> <z> <radius>
137136

138137
.then(argument("world|map", StringArgumentType.string()).suggests(new WorldOrMapSuggestionProvider<>(plugin))
139138
.executes(this::renderCommand) // /bluemap render <world|map>
140139

141140
.then(argument("x", DoubleArgumentType.doubleArg())
142141
.then(argument("z", DoubleArgumentType.doubleArg())
143142
.then(argument("radius", IntegerArgumentType.integer())
144-
.executes(this::renderCommand) // /bluemap render <world|map> <x> <z> <radius>
145-
)
146-
)
147-
)
148-
)
149-
143+
.executes(this::renderCommand))))) // /bluemap render <world|map> <x> <z> <radius>
150144
.build();
151145

152146
LiteralCommandNode<S> prioRenderCommand =
153147
literal("prioritize")
154148
.requires(requirements("bluemap.render"))
155149
.then(argument("uuid", StringArgumentType.string())
156-
.executes(this::prioritizeRenderTaskCommand)
157-
)
150+
.executes(this::prioritizeRenderTaskCommand))
158151
.build();
159152

160153
LiteralCommandNode<S> cancelRenderCommand =
161154
literal("cancel")
162155
.requires(requirements("bluemap.render"))
163156
.then(argument("uuid", StringArgumentType.string())
164-
.executes(this::cancelRenderTaskCommand)
165-
)
157+
.executes(this::cancelRenderTaskCommand))
166158
.build();
167159

168160
LiteralCommandNode<S> worldsCommand =
@@ -177,6 +169,34 @@ public void init() {
177169
.executes(this::mapsCommand)
178170
.build();
179171

172+
LiteralCommandNode<S> markerCommand =
173+
literal("marker")
174+
.requires(requirements("bluemap.marker"))
175+
.build();
176+
177+
LiteralCommandNode<S> createMarkerCommand =
178+
literal("create")
179+
.requires(requirements("bluemap.marker"))
180+
.then(argument("id", StringArgumentType.word())
181+
.then(argument("map", StringArgumentType.string()).suggests(new MapSuggestionProvider<>(plugin))
182+
183+
.then(argument("label", StringArgumentType.string())
184+
.executes(this::createMarkerCommand))
185+
186+
.then(argument("x", DoubleArgumentType.doubleArg())
187+
.then(argument("y", DoubleArgumentType.doubleArg())
188+
.then(argument("z", DoubleArgumentType.doubleArg())
189+
.then(argument("label", StringArgumentType.string())
190+
.executes(this::createMarkerCommand)))))))
191+
.build();
192+
193+
LiteralCommandNode<S> removeMarkerCommand =
194+
literal("remove")
195+
.requires(requirements("bluemap.marker"))
196+
.then(argument("id", StringArgumentType.word()).suggests(MarkerIdSuggestionProvider.getInstance())
197+
.executes(this::removeMarkerCommand))
198+
.build();
199+
180200
// command tree
181201
dispatcher.getRoot().addChild(baseCommand);
182202
baseCommand.addChild(reloadCommand);
@@ -188,6 +208,9 @@ public void init() {
188208
renderCommand.addChild(cancelRenderCommand);
189209
baseCommand.addChild(worldsCommand);
190210
baseCommand.addChild(mapsCommand);
211+
baseCommand.addChild(markerCommand);
212+
markerCommand.addChild(createMarkerCommand);
213+
markerCommand.addChild(removeMarkerCommand);
191214
}
192215

193216
private Predicate<S> requirements(String permission){
@@ -491,4 +514,112 @@ public int mapsCommand(CommandContext<S> context) {
491514
return 1;
492515
}
493516

517+
public int createMarkerCommand(CommandContext<S> context) {
518+
CommandSource source = commandSourceInterface.apply(context.getSource());
519+
520+
String markerId = context.getArgument("id", String.class);
521+
String markerLabel = context.getArgument("label", String.class)
522+
.replace("<", "&lt;")
523+
.replace(">", "&gt;"); //no html via commands
524+
525+
// parse world/map argument
526+
String mapString = context.getArgument("map", String.class);
527+
MapType map = parseMap(mapString).orElse(null);
528+
529+
if (map == null) {
530+
source.sendMessage(Text.of(TextColor.RED, "There is no ", helper.mapHelperHover(), " with this name: ", TextColor.WHITE, mapString));
531+
return 0;
532+
}
533+
534+
// parse position
535+
Optional<Double> x = getOptionalArgument(context, "x", Double.class);
536+
Optional<Double> y = getOptionalArgument(context, "y", Double.class);
537+
Optional<Double> z = getOptionalArgument(context, "z", Double.class);
538+
539+
Vector3d position;
540+
541+
if (x.isPresent() && y.isPresent() && z.isPresent()) {
542+
position = new Vector3d(x.get(), y.get(), z.get());
543+
} else {
544+
position = source.getPosition().orElse(null);
545+
546+
if (position == null) {
547+
source.sendMessage(Text.of(TextColor.RED, "Can't detect a position from this command-source, you'll have to define the x,y,z coordinates for the marker!").setHoverText(Text.of(TextColor.GRAY, "/bluemap marker create " + markerId + " " + "[world|map] <x> <y> <z> <label>")));
548+
return 0;
549+
}
550+
}
551+
552+
// get api
553+
BlueMapAPI api = BlueMapAPI.getInstance().orElse(null);
554+
if (api == null) {
555+
source.sendMessage(Text.of(TextColor.RED, "MarkerAPI is not available, try ", TextColor.GRAY, "/bluemap reload"));
556+
return 0;
557+
}
558+
559+
// resolve api-map
560+
Optional<BlueMapMap> apiMap = api.getMap(map.getId());
561+
if (!apiMap.isPresent()) {
562+
source.sendMessage(Text.of(TextColor.RED, "Failed to get map from API, try ", TextColor.GRAY, "/bluemap reload"));
563+
return 0;
564+
}
565+
566+
// add marker
567+
try {
568+
MarkerAPI markerApi = api.getMarkerAPI();
569+
570+
MarkerSet set = markerApi.getMarkerSet(DEFAULT_MARKER_SET_ID).orElse(null);
571+
if (set == null) {
572+
set = markerApi.createMarkerSet(DEFAULT_MARKER_SET_ID);
573+
set.setLabel("Markers");
574+
}
575+
576+
if (set.getMarker(markerId).isPresent()) {
577+
source.sendMessage(Text.of(TextColor.RED, "There already is a marker with this id: ", TextColor.WHITE, markerId));
578+
return 0;
579+
}
580+
581+
POIMarker marker = set.createPOIMarker(markerId, apiMap.get(), position);
582+
marker.setLabel(markerLabel);
583+
584+
markerApi.save();
585+
MarkerIdSuggestionProvider.getInstance().forceUpdate();
586+
} catch (IOException e) {
587+
source.sendMessage(Text.of(TextColor.RED, "There was an error trying to add the marker, please check the console for details!"));
588+
Logger.global.logError("Exception trying to add a marker!", e);
589+
}
590+
591+
source.sendMessage(Text.of(TextColor.GREEN, "Marker added!"));
592+
return 1;
593+
}
594+
595+
public int removeMarkerCommand(CommandContext<S> context) {
596+
CommandSource source = commandSourceInterface.apply(context.getSource());
597+
598+
String markerId = context.getArgument("id", String.class);
599+
600+
BlueMapAPI api = BlueMapAPI.getInstance().orElse(null);
601+
if (api == null) {
602+
source.sendMessage(Text.of(TextColor.RED, "MarkerAPI is not available, try ", TextColor.GRAY, "/bluemap reload"));
603+
return 0;
604+
}
605+
606+
try {
607+
MarkerAPI markerApi = api.getMarkerAPI();
608+
609+
MarkerSet set = markerApi.createMarkerSet("markers");
610+
if (!set.removeMarker(markerId)) {
611+
source.sendMessage(Text.of(TextColor.RED, "There is no marker with this id: ", TextColor.WHITE, markerId));
612+
}
613+
614+
markerApi.save();
615+
MarkerIdSuggestionProvider.getInstance().forceUpdate();
616+
} catch (IOException e) {
617+
source.sendMessage(Text.of(TextColor.RED, "There was an error trying to remove the marker, please check the console for details!"));
618+
Logger.global.logError("Exception trying to remove a marker!", e);
619+
}
620+
621+
source.sendMessage(Text.of(TextColor.GREEN, "Marker removed!"));
622+
return 1;
623+
}
624+
494625
}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*
2+
* This file is part of BlueMap, licensed under the MIT License (MIT).
3+
*
4+
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
5+
* Copyright (c) contributors
6+
*
7+
* Permission is hereby granted, free of charge, to any person obtaining a copy
8+
* of this software and associated documentation files (the "Software"), to deal
9+
* in the Software without restriction, including without limitation the rights
10+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
* copies of the Software, and to permit persons to whom the Software is
12+
* furnished to do so, subject to the following conditions:
13+
*
14+
* The above copyright notice and this permission notice shall be included in
15+
* all copies or substantial portions of the Software.
16+
*
17+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
* THE SOFTWARE.
24+
*/
25+
package de.bluecolored.bluemap.common.plugin.commands;
26+
27+
import java.io.IOException;
28+
import java.util.Collection;
29+
import java.util.HashSet;
30+
import java.util.Optional;
31+
32+
import de.bluecolored.bluemap.api.BlueMapAPI;
33+
import de.bluecolored.bluemap.api.marker.Marker;
34+
import de.bluecolored.bluemap.api.marker.MarkerAPI;
35+
import de.bluecolored.bluemap.api.marker.MarkerSet;
36+
import de.bluecolored.bluemap.api.marker.POIMarker;
37+
import de.bluecolored.bluemap.core.logger.Logger;
38+
39+
public class MarkerIdSuggestionProvider<S> extends AbstractSuggestionProvider<S> {
40+
41+
private static MarkerIdSuggestionProvider<?> instance;
42+
43+
private MarkerAPI markerApi;
44+
private long lastUpdate = -1;
45+
46+
private MarkerIdSuggestionProvider() {}
47+
48+
@Override
49+
public Collection<String> getPossibleValues() {
50+
Collection<String> values = new HashSet<>();
51+
52+
if (markerApi == null || lastUpdate + 1000 * 60 < System.currentTimeMillis()) { // only (re)load marker-values max every minute
53+
lastUpdate = System.currentTimeMillis();
54+
55+
Optional<BlueMapAPI> api = BlueMapAPI.getInstance();
56+
if (!api.isPresent()) return values;
57+
58+
try {
59+
markerApi = api.get().getMarkerAPI();
60+
} catch (IOException e) {
61+
Logger.global.noFloodError("0FEz5tm345rf", "Failed to load MarkerAPI!", e);
62+
return values;
63+
}
64+
}
65+
66+
MarkerSet set = markerApi.getMarkerSet(Commands.DEFAULT_MARKER_SET_ID).orElse(null);
67+
if (set != null) {
68+
for (Marker marker : set.getMarkers()) {
69+
if (marker instanceof POIMarker) {
70+
values.add(marker.getId());
71+
}
72+
}
73+
}
74+
75+
return values;
76+
}
77+
78+
public void forceUpdate() {
79+
lastUpdate = -1;
80+
}
81+
82+
@SuppressWarnings("unchecked")
83+
public static <S> MarkerIdSuggestionProvider<S> getInstance(){
84+
if (instance == null) {
85+
instance = new MarkerIdSuggestionProvider<>();
86+
}
87+
88+
return (MarkerIdSuggestionProvider<S>) instance;
89+
}
90+
91+
}

0 commit comments

Comments
 (0)