mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-22 18:45:21 +01:00
Rework commands
This commit is contained in:
parent
cf74a70f32
commit
a246da133c
@ -31,6 +31,7 @@ build.dependsOn shadowJar {
|
||||
relocate 'org.apache.commons.io', 'de.bluecolored.shadow.apache.commons.io'
|
||||
relocate 'org.apache.commons.lang3', 'de.bluecolored.shadow.apache.commons.lang3'
|
||||
relocate 'org.bstats.bukkit', 'de.bluecolored.shadow.bstats.bukkit'
|
||||
relocate 'com.mojang.brigadier', 'de.bluecolored.shadow.mojang.brigadier'
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
@ -24,18 +24,29 @@
|
||||
*/
|
||||
package de.bluecolored.bluemap.bukkit;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.command.BlockCommandSender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3d;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
public class BukkitCommandSource implements CommandSource {
|
||||
|
||||
private Plugin plugin;
|
||||
private CommandSender delegate;
|
||||
|
||||
public BukkitCommandSource(CommandSender delegate) {
|
||||
public BukkitCommandSource(Plugin plugin, CommandSender delegate) {
|
||||
this.plugin = plugin;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@ -54,4 +65,43 @@ public void sendMessage(Text text) {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return delegate.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Vector3d> getPosition() {
|
||||
Location location = getLocation();
|
||||
|
||||
if (location != null) {
|
||||
return Optional.of(new Vector3d(location.getX(), location.getY(), location.getZ()));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<World> getWorld() {
|
||||
Location location = getLocation();
|
||||
|
||||
if (location != null) {
|
||||
return Optional.ofNullable(plugin.getWorld(location.getWorld().getUID()));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Location getLocation() {
|
||||
Location location = null;
|
||||
if (delegate instanceof Entity) {
|
||||
location = ((Entity) delegate).getLocation();
|
||||
}
|
||||
if (delegate instanceof BlockCommandSender) {
|
||||
location = ((BlockCommandSender) delegate).getBlock().getLocation();
|
||||
}
|
||||
|
||||
return location;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,221 +25,93 @@
|
||||
package de.bluecolored.bluemap.bukkit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.UUID;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.command.defaults.BukkitCommand;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.server.TabCompleteEvent;
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Commands;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.common.plugin.text.TextColor;
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.common.plugin.commands.Commands;
|
||||
|
||||
public class BukkitCommands implements CommandExecutor {
|
||||
public class BukkitCommands implements Listener {
|
||||
|
||||
private Commands bluemapCommands;
|
||||
private CommandDispatcher<CommandSender> dispatcher;
|
||||
|
||||
private Collection<Command> commands;
|
||||
public BukkitCommands(final Plugin plugin) {
|
||||
this.dispatcher = new CommandDispatcher<>();
|
||||
|
||||
public BukkitCommands(Commands commands) {
|
||||
this.bluemapCommands = commands;
|
||||
this.commands = new ArrayList<>();
|
||||
initCommands();
|
||||
// register commands
|
||||
new Commands<>(plugin, dispatcher, bukkitSender -> new BukkitCommandSource(plugin, bukkitSender));
|
||||
}
|
||||
|
||||
private void initCommands() {
|
||||
public Collection<BukkitCommand> getRootCommands(){
|
||||
Collection<BukkitCommand> rootCommands = new ArrayList<>();
|
||||
|
||||
commands.add(new Command("bluemap.status") {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, CommandSource source, String[] args) {
|
||||
if (args.length != 0) return false;
|
||||
|
||||
bluemapCommands.executeRootCommand(source);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
commands.add(new Command("bluemap.reload", "reload") {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, CommandSource source, String[] args) {
|
||||
if (args.length != 0) return false;
|
||||
|
||||
bluemapCommands.executeReloadCommand(source);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
commands.add(new Command("bluemap.pause", "pause") {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, CommandSource source, String[] args) {
|
||||
if (args.length != 0) return false;
|
||||
|
||||
bluemapCommands.executePauseCommand(source);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
commands.add(new Command("bluemap.resume", "resume") {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, CommandSource source, String[] args) {
|
||||
if (args.length != 0) return false;
|
||||
|
||||
bluemapCommands.executeResumeCommand(source);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
commands.add(new Command("bluemap.render", "render") {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, CommandSource source, String[] args) {
|
||||
if (sender instanceof Player) {
|
||||
if (args.length > 2) return false;
|
||||
Player player = (Player) sender;
|
||||
|
||||
World world = null;
|
||||
int radius = -1;
|
||||
if (args.length >= 1) {
|
||||
world = Bukkit.getWorld(args[0]);
|
||||
}
|
||||
if (args.length == 2 || (args.length == 1 && world == null)) {
|
||||
try {
|
||||
radius = Integer.parseInt(args[args.length - 1]);
|
||||
} catch (NumberFormatException ex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (world == null){
|
||||
world = player.getWorld();
|
||||
}
|
||||
|
||||
if (radius >= 0) {
|
||||
Vector2i pos = new Vector2i(player.getLocation().getBlockX(), player.getLocation().getBlockZ());
|
||||
bluemapCommands.executeRenderWorldCommand(source, world.getUID(), pos, radius);
|
||||
} else {
|
||||
bluemapCommands.executeRenderWorldCommand(source, world.getUID());
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if (args.length != 1) return false;
|
||||
World world = Bukkit.getWorld(args[0]);
|
||||
|
||||
bluemapCommands.executeRenderWorldCommand(source, world.getUID());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
commands.add(new Command("bluemap.render", "render", "prioritize") {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, CommandSource source, String[] args) {
|
||||
if (args.length != 1) return false;
|
||||
|
||||
try {
|
||||
UUID uuid = UUID.fromString(args[0]);
|
||||
bluemapCommands.executePrioritizeRenderTaskCommand(source, uuid);
|
||||
return true;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "'" + args[0] + "' is not a valid UUID!"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
commands.add(new Command("bluemap.render", "render", "remove") {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, CommandSource source, String[] args) {
|
||||
if (args.length != 1) return false;
|
||||
|
||||
try {
|
||||
UUID uuid = UUID.fromString(args[0]);
|
||||
bluemapCommands.executeRemoveRenderTaskCommand(source, uuid);
|
||||
return true;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "'" + args[0] + "' is not a valid UUID!"));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
commands.add(new Command("bluemap.debug", "debug") {
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, CommandSource source, String[] args) {
|
||||
if (!(sender instanceof Player)) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "You have to be a player to use this command!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
Player player = (Player) sender;
|
||||
UUID world = player.getWorld().getUID();
|
||||
Vector3i pos = new Vector3i(
|
||||
player.getLocation().getBlockX(),
|
||||
player.getLocation().getBlockY(),
|
||||
player.getLocation().getBlockZ()
|
||||
);
|
||||
|
||||
bluemapCommands.executeDebugCommand(source, world, pos);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
for (CommandNode<CommandSender> node : this.dispatcher.getRoot().getChildren()) {
|
||||
rootCommands.add(new CommandProxy(node.getName()));
|
||||
}
|
||||
|
||||
return rootCommands;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCommand(CommandSender sender, org.bukkit.command.Command bukkitCommand, String label, String[] args) {
|
||||
int max = -1;
|
||||
Command maxCommand = null;
|
||||
for (Command command : commands) {
|
||||
int matchSize = command.matches(args);
|
||||
if (matchSize > max) {
|
||||
maxCommand = command;
|
||||
max = matchSize;
|
||||
@EventHandler
|
||||
public void onTabComplete(TabCompleteEvent evt) {
|
||||
try {
|
||||
Suggestions suggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(evt.getBuffer().substring(1), evt.getSender())).get(100, TimeUnit.MILLISECONDS);
|
||||
List<String> completions = new ArrayList<>();
|
||||
for (Suggestion suggestion : suggestions.getList()) {
|
||||
String text = suggestion.getText();
|
||||
|
||||
if (text.indexOf(' ') == -1) {
|
||||
completions.add(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (maxCommand == null) return false;
|
||||
|
||||
BukkitCommandSource source = new BukkitCommandSource(sender);
|
||||
|
||||
if (!maxCommand.checkPermission(sender)) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "You don't have permission to use this command!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
return maxCommand.execute(sender, source, Arrays.copyOfRange(args, max, args.length));
|
||||
if (!completions.isEmpty()) {
|
||||
completions.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
|
||||
evt.setCompletions(completions);
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException ignore) {}
|
||||
}
|
||||
|
||||
private abstract class Command {
|
||||
private class CommandProxy extends BukkitCommand {
|
||||
|
||||
private String[] command;
|
||||
private String permission;
|
||||
|
||||
public Command(String permission, String... command) {
|
||||
this.command = command;
|
||||
protected CommandProxy(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public abstract boolean execute(CommandSender sender, CommandSource source, String[] args);
|
||||
|
||||
public int matches(String[] args) {
|
||||
if (args.length < command.length) return -1;
|
||||
|
||||
for (int i = 0; i < command.length; i++) {
|
||||
if (!args[i].equalsIgnoreCase(command[i])) return -1;
|
||||
@Override
|
||||
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||
String command = commandLabel;
|
||||
if (args.length > 0) {
|
||||
command += " " + StringUtils.join(args, ' ');
|
||||
}
|
||||
|
||||
return command.length;
|
||||
}
|
||||
try {
|
||||
return dispatcher.execute(command, sender) > 0;
|
||||
} catch (CommandSyntaxException ex) {
|
||||
sender.sendMessage(ChatColor.RED + ex.getRawMessage().getString());
|
||||
|
||||
public boolean checkPermission(CommandSender sender) {
|
||||
if (sender.isOp()) return true;
|
||||
return sender.hasPermission(permission);
|
||||
String context = ex.getContext();
|
||||
if (context != null) sender.sendMessage(ChatColor.GRAY + context);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
@ -34,6 +35,8 @@
|
||||
import org.bstats.bukkit.MetricsLite;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandMap;
|
||||
import org.bukkit.command.defaults.BukkitCommand;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
@ -54,7 +57,7 @@ public BukkitPlugin() {
|
||||
|
||||
this.eventForwarder = new EventForwarder();
|
||||
this.bluemap = new Plugin("bukkit", this);
|
||||
this.commands = new BukkitCommands(bluemap.getCommands());
|
||||
this.commands = new BukkitCommands(this.bluemap);
|
||||
|
||||
BukkitPlugin.instance = this;
|
||||
}
|
||||
@ -69,9 +72,27 @@ public void onEnable() {
|
||||
world.save();
|
||||
}
|
||||
|
||||
//register events
|
||||
getServer().getPluginManager().registerEvents(eventForwarder, this);
|
||||
getCommand("bluemap").setExecutor(commands);
|
||||
|
||||
//register commands
|
||||
try {
|
||||
final Field bukkitCommandMap = Bukkit.getServer().getClass().getDeclaredField("commandMap");
|
||||
|
||||
bukkitCommandMap.setAccessible(true);
|
||||
CommandMap commandMap = (CommandMap) bukkitCommandMap.get(Bukkit.getServer());
|
||||
|
||||
for (BukkitCommand command : commands.getRootCommands()) {
|
||||
commandMap.register(command.getLabel(), command);
|
||||
}
|
||||
} catch(NoSuchFieldException | SecurityException | IllegalAccessException e) {
|
||||
Logger.global.logError("Failed to register commands!", e);
|
||||
}
|
||||
|
||||
//tab completions
|
||||
getServer().getPluginManager().registerEvents(commands, this);
|
||||
|
||||
//load bluemap
|
||||
getServer().getScheduler().runTaskAsynchronously(this, () -> {
|
||||
try {
|
||||
Logger.global.logInfo("Loading...");
|
||||
|
@ -6,16 +6,6 @@ author: "Blue (TBlueF / Lukas Rieger)"
|
||||
authors: [Blue (TBlueF / Lukas Rieger)]
|
||||
website: "https://github.com/BlueMap-Minecraft"
|
||||
commands:
|
||||
bluemap:
|
||||
description: Root command for all bluemap commands
|
||||
permission: bluemap
|
||||
usage: |
|
||||
/<command>
|
||||
/<command> reload
|
||||
/<command> pause
|
||||
/<command> resume
|
||||
/<command> render [world] [block-radius]
|
||||
/<command> debug
|
||||
permissions:
|
||||
bluemap.*:
|
||||
children:
|
||||
|
@ -1,4 +1,7 @@
|
||||
dependencies {
|
||||
compile 'com.mojang:brigadier:1.0.17'
|
||||
|
||||
compile project(':BlueMapCore')
|
||||
compile project(':BlueMapAPI')
|
||||
}
|
||||
|
||||
|
@ -1,400 +0,0 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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 de.bluecolored.bluemap.common.plugin;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.commons.lang3.time.DurationFormatUtils;
|
||||
|
||||
import com.flowpowered.math.GenericMath;
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.google.common.collect.Lists;
|
||||
|
||||
import de.bluecolored.bluemap.common.MapType;
|
||||
import de.bluecolored.bluemap.common.RenderManager;
|
||||
import de.bluecolored.bluemap.common.RenderTask;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.common.plugin.text.TextColor;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.mca.Chunk;
|
||||
import de.bluecolored.bluemap.core.mca.ChunkAnvil112;
|
||||
import de.bluecolored.bluemap.core.mca.MCAWorld;
|
||||
import de.bluecolored.bluemap.core.render.hires.HiresModelManager;
|
||||
import de.bluecolored.bluemap.core.world.Block;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
/**
|
||||
* Commands:
|
||||
*
|
||||
* <ul>
|
||||
* <li>/bluemap</li>
|
||||
* <li>/bluemap reload</li>
|
||||
* <li>/bluemap pause</li>
|
||||
* <li>/bluemap resume</li>
|
||||
* <li>/bluemap render [world]</li>
|
||||
* <li>/bluemap render prioritize [task-uuid]</li>
|
||||
* <li>/bluemap render remove [task-uuid]</li>
|
||||
* <li>/bluemap debug</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class Commands {
|
||||
|
||||
private Plugin bluemap;
|
||||
|
||||
public Commands(Plugin bluemap) {
|
||||
this.bluemap = bluemap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap
|
||||
*/
|
||||
public void executeRootCommand(CommandSource source) {
|
||||
if (!checkLoaded(source)) return;
|
||||
|
||||
source.sendMessages(createStatusMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap debug
|
||||
*/
|
||||
public boolean executeDebugCommand(CommandSource source, UUID worldUuid, Vector3i playerPosition) {
|
||||
if (!checkLoaded(source)) return false;
|
||||
|
||||
World world = bluemap.getWorld(worldUuid);
|
||||
|
||||
if (world == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "This world is not loaded with BlueMap! Maybe it is not configured?"));
|
||||
return false;
|
||||
}
|
||||
|
||||
Block block = world.getBlock(playerPosition);
|
||||
Block blockBelow = world.getBlock(playerPosition.add(0, -1, 0));
|
||||
|
||||
String blockIdMeta = "";
|
||||
String blockBelowIdMeta = "";
|
||||
|
||||
if (world instanceof MCAWorld) {
|
||||
try {
|
||||
Chunk chunk = ((MCAWorld) world).getChunk(MCAWorld.blockToChunk(playerPosition));
|
||||
if (chunk instanceof ChunkAnvil112) {
|
||||
blockIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(playerPosition) + ")";
|
||||
blockBelowIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(playerPosition.add(0, -1, 0)) + ")";
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.global.logError("Failed to read chunk for debug!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
source.sendMessages(Lists.newArrayList(
|
||||
Text.of(TextColor.GOLD, "Block at you: ", TextColor.WHITE, block, TextColor.GRAY, blockIdMeta),
|
||||
Text.of(TextColor.GOLD, "Block below you: ", TextColor.WHITE, blockBelow, TextColor.GRAY, blockBelowIdMeta)
|
||||
));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap reload
|
||||
*/
|
||||
public void executeReloadCommand(CommandSource source) {
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Reloading BlueMap..."));
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
bluemap.reload();
|
||||
|
||||
if (bluemap.isLoaded()) {
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "BlueMap reloaded!"));
|
||||
} else {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Could not load BlueMap! See the console for details!"));
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.global.logError("Failed to reload BlueMap!", ex);
|
||||
|
||||
source.sendMessage(Text.of(TextColor.RED, "There was an error reloading BlueMap! See the console for details!"));
|
||||
}
|
||||
}).start();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap pause
|
||||
*/
|
||||
public boolean executePauseCommand(CommandSource source) {
|
||||
if (!checkLoaded(source)) return false;
|
||||
|
||||
if (bluemap.getRenderManager().isRunning()) {
|
||||
bluemap.getRenderManager().stop();
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "BlueMap rendering paused!"));
|
||||
return true;
|
||||
} else {
|
||||
source.sendMessage(Text.of(TextColor.RED, "BlueMap rendering are already paused!"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap resume
|
||||
*/
|
||||
public boolean executeResumeCommand(CommandSource source) {
|
||||
if (!checkLoaded(source)) return false;
|
||||
|
||||
if (!bluemap.getRenderManager().isRunning()) {
|
||||
bluemap.getRenderManager().start();
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "BlueMap renders resumed!"));
|
||||
return true;
|
||||
} else {
|
||||
source.sendMessage(Text.of(TextColor.RED, "BlueMap renders are already running!"));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap render [world,map]
|
||||
*/
|
||||
public boolean executeRenderCommand(CommandSource source, String mapOrWorld) {
|
||||
return executeRenderCommand(source, mapOrWorld, null, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap render [world,map] [block-radius]
|
||||
*/
|
||||
public boolean executeRenderCommand(CommandSource source, String mapOrWorld, Vector2i center, int blockRadius) {
|
||||
if (!checkLoaded(source)) return false;
|
||||
|
||||
MapType map = null;
|
||||
World world = null;
|
||||
for (MapType m : bluemap.getMapTypes()) {
|
||||
if (mapOrWorld.equalsIgnoreCase(m.getId()) || mapOrWorld.equalsIgnoreCase(m.getName())){
|
||||
map = m;
|
||||
world = map.getWorld();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (world == null) {
|
||||
for (World w : bluemap.getWorlds()) {
|
||||
if (mapOrWorld.equalsIgnoreCase(w.getName())){
|
||||
world = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (world == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Could not find a world or map with this name or id ", TextColor.GRAY, "('" + mapOrWorld + "')", TextColor.RED, "! Maybe it is not configured in BlueMap's config?"));
|
||||
}
|
||||
|
||||
world.invalidateChunkCache();
|
||||
|
||||
final World worldToRender = world;
|
||||
final MapType mapToRender = map;
|
||||
if (mapToRender == null) {
|
||||
new Thread(() -> {
|
||||
createWorldRenderTask(source, worldToRender, center, blockRadius);
|
||||
}).start();
|
||||
} else {
|
||||
new Thread(() -> {
|
||||
createMapRenderTask(source, mapToRender, center, blockRadius);
|
||||
}).start();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap render [world]
|
||||
*/
|
||||
public boolean executeRenderWorldCommand(CommandSource source, UUID worldUuid) {
|
||||
return executeRenderWorldCommand(source, worldUuid, null, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap render [world] [block-radius]
|
||||
*/
|
||||
public boolean executeRenderWorldCommand(CommandSource source, UUID worldUuid, Vector2i center, int blockRadius) {
|
||||
if (!checkLoaded(source)) return false;
|
||||
|
||||
World world = bluemap.getWorld(worldUuid);
|
||||
|
||||
if (world == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "This world is not loaded with BlueMap! Maybe it is not configured in BlueMap's config?"));
|
||||
return false;
|
||||
}
|
||||
|
||||
world.invalidateChunkCache();
|
||||
|
||||
new Thread(() -> {
|
||||
createWorldRenderTask(source, world, center, blockRadius);
|
||||
}).start();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap render prioritize [task-uuid]
|
||||
*/
|
||||
public void executePrioritizeRenderTaskCommand(CommandSource source, UUID taskUUID) {
|
||||
if (!checkLoaded(source)) return;
|
||||
|
||||
for (RenderTask task : bluemap.getRenderManager().getRenderTasks()) {
|
||||
if (task.getUuid().equals(taskUUID)) {
|
||||
bluemap.getRenderManager().prioritizeRenderTask(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
source.sendMessages(createStatusMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* Command: /bluemap render remove [task-uuid]
|
||||
*/
|
||||
public void executeRemoveRenderTaskCommand(CommandSource source, UUID taskUUID) {
|
||||
if (!checkLoaded(source)) return;
|
||||
|
||||
for (RenderTask task : bluemap.getRenderManager().getRenderTasks()) {
|
||||
if (task.getUuid().equals(taskUUID)) {
|
||||
bluemap.getRenderManager().removeRenderTask(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
source.sendMessages(createStatusMessage());
|
||||
}
|
||||
|
||||
private List<Text> createStatusMessage(){
|
||||
List<Text> lines = new ArrayList<>();
|
||||
|
||||
RenderManager renderer = bluemap.getRenderManager();
|
||||
|
||||
lines.add(Text.of());
|
||||
lines.add(Text.of(TextColor.BLUE, "Tile-Updates:"));
|
||||
|
||||
if (renderer.isRunning()) {
|
||||
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ", Text.of(TextColor.GREEN, "running").setHoverText(Text.of("click to pause rendering")).setClickCommand("/bluemap pause"), TextColor.GRAY, "!"));
|
||||
} else {
|
||||
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ", Text.of(TextColor.RED, "paused").setHoverText(Text.of("click to resume rendering")).setClickCommand("/bluemap resume"), TextColor.GRAY, "!"));
|
||||
}
|
||||
|
||||
lines.add(Text.of(TextColor.WHITE, " Scheduled tile-updates: ", Text.of(TextColor.GOLD, renderer.getQueueSize()).setHoverText(Text.of("tiles waiting for a free render-thread")), TextColor.GRAY, " + " , Text.of(TextColor.GRAY, bluemap.getUpdateHandler().getUpdateBufferCount()).setHoverText(Text.of("tiles waiting for world-save"))));
|
||||
|
||||
RenderTask[] tasks = renderer.getRenderTasks();
|
||||
if (tasks.length > 0) {
|
||||
RenderTask task = tasks[0];
|
||||
|
||||
long time = task.getActiveTime();
|
||||
String durationString = DurationFormatUtils.formatDurationWords(time, true, true);
|
||||
double pct = (double)task.getRenderedTileCount() / (double)(task.getRenderedTileCount() + task.getRemainingTileCount());
|
||||
|
||||
long ert = (long)((time / pct) * (1d - pct));
|
||||
String ertDurationString = DurationFormatUtils.formatDurationWords(ert, true, true);
|
||||
|
||||
double tps = task.getRenderedTileCount() / (time / 1000.0);
|
||||
|
||||
lines.add(Text.of(TextColor.BLUE, "Current task:"));
|
||||
lines.add(Text.of(" ", createCancelTaskText(task), TextColor.WHITE, " Task ", TextColor.GOLD, task.getName(), TextColor.WHITE, " for map ", Text.of(TextColor.GOLD, task.getMapType().getName()).setHoverText(Text.of(TextColor.WHITE, "World: ", TextColor.GOLD, task.getMapType().getWorld().getName()))));
|
||||
lines.add(Text.of(TextColor.WHITE, " rendered ", TextColor.GOLD, task.getRenderedTileCount(), TextColor.WHITE, " tiles ", TextColor.GRAY, "(" + (Math.round(pct * 1000)/10.0) + "% | " + GenericMath.round(tps, 1) + "t/s)", TextColor.WHITE, " in ", TextColor.GOLD, durationString));
|
||||
lines.add(Text.of(TextColor.WHITE, " with ", TextColor.GOLD, task.getRemainingTileCount(), TextColor.WHITE, " tiles to go. ETA: ", TextColor.GOLD, ertDurationString));
|
||||
}
|
||||
|
||||
if (tasks.length > 1) {
|
||||
lines.add(Text.of(TextColor.BLUE, "Waiting tasks:"));
|
||||
for (int i = 1; i < tasks.length; i++) {
|
||||
RenderTask task = tasks[i];
|
||||
lines.add(Text.of(" ", createCancelTaskText(task), createPrioritizeTaskText(task), TextColor.WHITE, " Task ", TextColor.GOLD, task.getName(), TextColor.WHITE, " for map ", Text.of(TextColor.GOLD, task.getMapType().getName()).setHoverText(Text.of(TextColor.WHITE, "World: ", TextColor.GOLD, task.getMapType().getWorld().getName())), TextColor.GRAY, " (" + task.getRemainingTileCount() + " tiles)"));
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
private Text createCancelTaskText(RenderTask task) {
|
||||
return Text.of(TextColor.RED, "[X]").setHoverText(Text.of(TextColor.GRAY, "click to remove this render-task")).setClickCommand("/bluemap render remove " + task.getUuid());
|
||||
}
|
||||
|
||||
private Text createPrioritizeTaskText(RenderTask task) {
|
||||
return Text.of(TextColor.GREEN, "[^]").setHoverText(Text.of(TextColor.GRAY, "click to prioritize this render-task")).setClickCommand("/bluemap render prioritize " + task.getUuid());
|
||||
}
|
||||
|
||||
private void createWorldRenderTask(CommandSource source, World world, Vector2i center, long blockRadius) {
|
||||
|
||||
for (MapType map : bluemap.getMapTypes()) {
|
||||
if (!map.getWorld().getUUID().equals(world.getUUID())) continue;
|
||||
|
||||
createMapRenderTask(source, map, center, blockRadius);
|
||||
}
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "All render tasks created! Use /bluemap to view the progress!"));
|
||||
}
|
||||
|
||||
private void createMapRenderTask(CommandSource source, MapType map, Vector2i center, long blockRadius) {
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Creating render-task for map: " + map.getId()));
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Collecting chunks..."));
|
||||
|
||||
String taskName = "world-render";
|
||||
|
||||
Predicate<Vector2i> filter;
|
||||
if (center == null || blockRadius < 0) {
|
||||
filter = c -> true;
|
||||
} else {
|
||||
filter = c -> c.mul(16).distanceSquared(center) <= blockRadius * blockRadius;
|
||||
taskName = "radius-render";
|
||||
}
|
||||
|
||||
Collection<Vector2i> chunks = map.getWorld().getChunkList(filter);
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GREEN, chunks.size() + " chunks found!"));
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Collecting tiles..."));
|
||||
|
||||
HiresModelManager hmm = map.getTileRenderer().getHiresModelManager();
|
||||
Collection<Vector2i> tiles = hmm.getTilesForChunks(chunks);
|
||||
|
||||
RenderTask task = new RenderTask(taskName, map);
|
||||
task.addTiles(tiles);
|
||||
task.optimizeQueue();
|
||||
bluemap.getRenderManager().addRenderTask(task);
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GREEN, tiles.size() + " tiles found! Task created."));
|
||||
}
|
||||
|
||||
private boolean checkLoaded(CommandSource source) {
|
||||
if (!bluemap.isLoaded()) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "BlueMap is not loaded!", TextColor.GRAY, "(Try /bluemap reload)"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
@ -80,7 +80,6 @@ public class Plugin {
|
||||
private String implementationType;
|
||||
|
||||
private ServerInterface serverInterface;
|
||||
private Commands commands;
|
||||
|
||||
private MainConfig config;
|
||||
private ResourcePack resourcePack;
|
||||
@ -102,7 +101,6 @@ public Plugin(String implementationType, ServerInterface serverInterface) {
|
||||
this.implementationType = implementationType.toLowerCase();
|
||||
|
||||
this.serverInterface = serverInterface;
|
||||
this.commands = new Commands(this);
|
||||
|
||||
this.maps = new HashMap<>();
|
||||
this.worlds = new HashMap<>();
|
||||
@ -393,10 +391,6 @@ public ServerInterface getServerInterface() {
|
||||
return serverInterface;
|
||||
}
|
||||
|
||||
public Commands getCommands() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
public MainConfig getMainConfig() {
|
||||
return config;
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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 de.bluecolored.bluemap.common.plugin.commands;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.suggestion.SuggestionProvider;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
|
||||
|
||||
public abstract class AbstractSuggestionProvider<S> implements SuggestionProvider<S> {
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Suggestions> getSuggestions(CommandContext<S> context, SuggestionsBuilder builder) throws CommandSyntaxException {
|
||||
Collection<String> possibleValues = getPossibleValues();
|
||||
if(possibleValues.isEmpty()) return Suggestions.empty();
|
||||
|
||||
String remaining = builder.getRemaining().toLowerCase();
|
||||
for (String str : possibleValues) {
|
||||
if (str.toLowerCase().startsWith(remaining)) {
|
||||
builder.suggest(str);
|
||||
}
|
||||
}
|
||||
|
||||
return builder.buildFuture();
|
||||
}
|
||||
|
||||
public abstract Collection<String> getPossibleValues();
|
||||
|
||||
}
|
@ -0,0 +1,185 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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 de.bluecolored.bluemap.common.plugin.commands;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.StringJoiner;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.apache.commons.lang3.time.DurationFormatUtils;
|
||||
|
||||
import com.flowpowered.math.GenericMath;
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
|
||||
import de.bluecolored.bluemap.common.MapType;
|
||||
import de.bluecolored.bluemap.common.RenderManager;
|
||||
import de.bluecolored.bluemap.common.RenderTask;
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.common.plugin.text.TextColor;
|
||||
import de.bluecolored.bluemap.core.render.hires.HiresModelManager;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
public class CommandHelper {
|
||||
|
||||
private Plugin plugin;
|
||||
|
||||
public CommandHelper(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public List<Text> createStatusMessage(){
|
||||
List<Text> lines = new ArrayList<>();
|
||||
|
||||
RenderManager renderer = plugin.getRenderManager();
|
||||
|
||||
lines.add(Text.of());
|
||||
lines.add(Text.of(TextColor.BLUE, "Tile-Updates:"));
|
||||
|
||||
if (renderer.isRunning()) {
|
||||
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ", Text.of(TextColor.GREEN, "running").setHoverText(Text.of("click to pause rendering")).setClickCommand("/bluemap pause"), TextColor.GRAY, "!"));
|
||||
} else {
|
||||
lines.add(Text.of(TextColor.WHITE, " Render-Threads are ", Text.of(TextColor.RED, "paused").setHoverText(Text.of("click to resume rendering")).setClickCommand("/bluemap resume"), TextColor.GRAY, "!"));
|
||||
}
|
||||
|
||||
lines.add(Text.of(TextColor.WHITE, " Scheduled tile-updates: ", Text.of(TextColor.GOLD, renderer.getQueueSize()).setHoverText(Text.of("tiles waiting for a free render-thread")), TextColor.GRAY, " + " , Text.of(TextColor.GRAY, plugin.getUpdateHandler().getUpdateBufferCount()).setHoverText(Text.of("tiles waiting for world-save"))));
|
||||
|
||||
RenderTask[] tasks = renderer.getRenderTasks();
|
||||
if (tasks.length > 0) {
|
||||
RenderTask task = tasks[0];
|
||||
|
||||
long time = task.getActiveTime();
|
||||
String durationString = DurationFormatUtils.formatDurationWords(time, true, true);
|
||||
double pct = (double)task.getRenderedTileCount() / (double)(task.getRenderedTileCount() + task.getRemainingTileCount());
|
||||
|
||||
long ert = (long)((time / pct) * (1d - pct));
|
||||
String ertDurationString = DurationFormatUtils.formatDurationWords(ert, true, true);
|
||||
|
||||
double tps = task.getRenderedTileCount() / (time / 1000.0);
|
||||
|
||||
lines.add(Text.of(TextColor.BLUE, "Current task:"));
|
||||
lines.add(Text.of(" ", createCancelTaskText(task), TextColor.WHITE, " Task ", TextColor.GOLD, task.getName(), TextColor.WHITE, " for map ", Text.of(TextColor.GOLD, task.getMapType().getName()).setHoverText(Text.of(TextColor.WHITE, "World: ", TextColor.GOLD, task.getMapType().getWorld().getName()))));
|
||||
lines.add(Text.of(TextColor.WHITE, " rendered ", TextColor.GOLD, task.getRenderedTileCount(), TextColor.WHITE, " tiles ", TextColor.GRAY, "(" + (Math.round(pct * 1000)/10.0) + "% | " + GenericMath.round(tps, 1) + "t/s)", TextColor.WHITE, " in ", TextColor.GOLD, durationString));
|
||||
lines.add(Text.of(TextColor.WHITE, " with ", TextColor.GOLD, task.getRemainingTileCount(), TextColor.WHITE, " tiles to go. ETA: ", TextColor.GOLD, ertDurationString));
|
||||
}
|
||||
|
||||
if (tasks.length > 1) {
|
||||
lines.add(Text.of(TextColor.BLUE, "Waiting tasks:"));
|
||||
for (int i = 1; i < tasks.length; i++) {
|
||||
RenderTask task = tasks[i];
|
||||
lines.add(Text.of(" ", createCancelTaskText(task), createPrioritizeTaskText(task), TextColor.WHITE, " Task ", TextColor.GOLD, task.getName(), TextColor.WHITE, " for map ", Text.of(TextColor.GOLD, task.getMapType().getName()).setHoverText(Text.of(TextColor.WHITE, "World: ", TextColor.GOLD, task.getMapType().getWorld().getName())), TextColor.GRAY, " (" + task.getRemainingTileCount() + " tiles)"));
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
private Text createCancelTaskText(RenderTask task) {
|
||||
return Text.of(TextColor.RED, "[X]").setHoverText(Text.of(TextColor.GRAY, "click to cancel this render-task")).setClickCommand("/bluemap render cancel " + task.getUuid());
|
||||
}
|
||||
|
||||
private Text createPrioritizeTaskText(RenderTask task) {
|
||||
return Text.of(TextColor.GREEN, "[^]").setHoverText(Text.of(TextColor.GRAY, "click to prioritize this render-task")).setClickCommand("/bluemap render prioritize " + task.getUuid());
|
||||
}
|
||||
|
||||
public void createWorldRenderTask(CommandSource source, World world, Vector2i center, long blockRadius) {
|
||||
|
||||
for (MapType map : plugin.getMapTypes()) {
|
||||
if (!map.getWorld().getUUID().equals(world.getUUID())) continue;
|
||||
|
||||
createMapRenderTask(source, map, center, blockRadius);
|
||||
}
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "All render tasks created! Use /bluemap to view the progress!"));
|
||||
}
|
||||
|
||||
public void createMapRenderTask(CommandSource source, MapType map, Vector2i center, long blockRadius) {
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Creating render-task for map: " + map.getId()));
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Collecting chunks..."));
|
||||
|
||||
String taskName = "world-render";
|
||||
|
||||
Predicate<Vector2i> filter;
|
||||
if (center == null || blockRadius < 0) {
|
||||
filter = c -> true;
|
||||
} else {
|
||||
filter = c -> c.mul(16).distanceSquared(center) <= blockRadius * blockRadius;
|
||||
taskName = "radius-render";
|
||||
}
|
||||
|
||||
Collection<Vector2i> chunks = map.getWorld().getChunkList(filter);
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GREEN, chunks.size() + " chunks found!"));
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Collecting tiles..."));
|
||||
|
||||
HiresModelManager hmm = map.getTileRenderer().getHiresModelManager();
|
||||
Collection<Vector2i> tiles = hmm.getTilesForChunks(chunks);
|
||||
|
||||
RenderTask task = new RenderTask(taskName, map);
|
||||
task.addTiles(tiles);
|
||||
task.optimizeQueue();
|
||||
plugin.getRenderManager().addRenderTask(task);
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GREEN, tiles.size() + " tiles found! Task created."));
|
||||
}
|
||||
|
||||
public Text worldHelperHover() {
|
||||
StringJoiner joiner = new StringJoiner("\n");
|
||||
for (World world : plugin.getWorlds()) {
|
||||
joiner.add(world.getName());
|
||||
}
|
||||
|
||||
return Text.of("world").setHoverText(Text.of(TextColor.WHITE, "Available worlds: \n", TextColor.GRAY, joiner.toString()));
|
||||
}
|
||||
|
||||
public Text mapHelperHover() {
|
||||
StringJoiner joiner = new StringJoiner("\n");
|
||||
for (MapType map : plugin.getMapTypes()) {
|
||||
joiner.add(map.getId());
|
||||
}
|
||||
|
||||
return Text.of("map").setHoverText(Text.of(TextColor.WHITE, "Available maps: \n", TextColor.GRAY, joiner.toString()));
|
||||
}
|
||||
|
||||
public boolean checkLoaded(CommandSource source) {
|
||||
if (!plugin.isLoaded()) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "BlueMap is not loaded!", TextColor.GRAY, "(Try /bluemap reload)"));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean checkPermission(CommandSource source, String permission) {
|
||||
if (source.hasPermission(permission)) return true;
|
||||
|
||||
source.sendMessage(Text.of(TextColor.RED, "You don't have the permissions to use this command!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,457 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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 de.bluecolored.bluemap.common.plugin.commands;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import com.flowpowered.math.vector.Vector3d;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.arguments.DoubleArgumentType;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.tree.LiteralCommandNode;
|
||||
|
||||
import de.bluecolored.bluemap.common.MapType;
|
||||
import de.bluecolored.bluemap.common.RenderTask;
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.common.plugin.text.TextColor;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.core.mca.Chunk;
|
||||
import de.bluecolored.bluemap.core.mca.ChunkAnvil112;
|
||||
import de.bluecolored.bluemap.core.mca.MCAWorld;
|
||||
import de.bluecolored.bluemap.core.world.Block;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
public class Commands<S> {
|
||||
|
||||
private final Plugin plugin;
|
||||
private final CommandDispatcher<S> dispatcher;
|
||||
private Function<S, CommandSource> commandSourceInterface;
|
||||
|
||||
private CommandHelper helper;
|
||||
|
||||
public Commands(Plugin plugin, CommandDispatcher<S> dispatcher, Function<S, CommandSource> commandSourceInterface) {
|
||||
this.plugin = plugin;
|
||||
this.dispatcher = dispatcher;
|
||||
this.commandSourceInterface = commandSourceInterface;
|
||||
|
||||
this.helper = new CommandHelper(plugin);
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
public void init() {
|
||||
// commands
|
||||
LiteralCommandNode<S> baseCommand =
|
||||
literal("bluemap")
|
||||
.requires(requirements("bluemap.status"))
|
||||
.executes(this::statusCommand)
|
||||
.build();
|
||||
|
||||
LiteralCommandNode<S> reloadCommand =
|
||||
literal("reload")
|
||||
.requires(requirementsUnloaded("bluemap.reload"))
|
||||
.executes(this::reloadCommand)
|
||||
.build();
|
||||
|
||||
LiteralCommandNode<S> debugCommand =
|
||||
literal("debug")
|
||||
.requires(requirements("bluemap.debug"))
|
||||
.executes(this::debugCommand)
|
||||
|
||||
.then(argument("world", StringArgumentType.word()).suggests(new WorldSuggestionProvider<>(plugin))
|
||||
.then(argument("x", DoubleArgumentType.doubleArg())
|
||||
.then(argument("y", DoubleArgumentType.doubleArg())
|
||||
.then(argument("z", DoubleArgumentType.doubleArg())
|
||||
.executes(this::debugCommand)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.build();
|
||||
|
||||
LiteralCommandNode<S> pauseCommand =
|
||||
literal("pause")
|
||||
.requires(requirements("bluemap.pause"))
|
||||
.executes(this::pauseCommand)
|
||||
.build();
|
||||
|
||||
LiteralCommandNode<S> resumeCommand =
|
||||
literal("resume")
|
||||
.requires(requirements("bluemap.resume"))
|
||||
.executes(this::resumeCommand)
|
||||
.build();
|
||||
|
||||
LiteralCommandNode<S> renderCommand =
|
||||
literal("render")
|
||||
.requires(requirements("bluemap.render"))
|
||||
.executes(this::renderCommand) // /bluemap render
|
||||
|
||||
.then(argument("radius", IntegerArgumentType.integer())
|
||||
.executes(this::renderCommand) // /bluemap render <radius>
|
||||
)
|
||||
|
||||
.then(argument("x", DoubleArgumentType.doubleArg())
|
||||
.then(argument("z", DoubleArgumentType.doubleArg())
|
||||
.then(argument("radius", IntegerArgumentType.integer())
|
||||
.executes(this::renderCommand) // /bluemap render <x> <z> <radius>
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
.then(argument("world|map", StringArgumentType.word()).suggests(new WorldOrMapSuggestionProvider<>(plugin))
|
||||
.executes(this::renderCommand) // /bluemap render <world|map>
|
||||
|
||||
.then(argument("x", DoubleArgumentType.doubleArg())
|
||||
.then(argument("z", DoubleArgumentType.doubleArg())
|
||||
.then(argument("radius", IntegerArgumentType.integer())
|
||||
.executes(this::renderCommand) // /bluemap render <world|map> <x> <z> <radius>
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
.build();
|
||||
|
||||
LiteralCommandNode<S> prioRenderCommand =
|
||||
literal("prioritize")
|
||||
.requires(requirements("bluemap.render"))
|
||||
.then(argument("uuid", StringArgumentType.word())
|
||||
.executes(this::prioritizeRenderTaskCommand)
|
||||
)
|
||||
.build();
|
||||
|
||||
LiteralCommandNode<S> cancelRenderCommand =
|
||||
literal("cancel")
|
||||
.requires(requirements("bluemap.render"))
|
||||
.then(argument("uuid", StringArgumentType.word())
|
||||
.executes(this::cancelRenderTaskCommand)
|
||||
)
|
||||
.build();
|
||||
|
||||
// command tree
|
||||
dispatcher.getRoot().addChild(baseCommand);
|
||||
baseCommand.addChild(reloadCommand);
|
||||
baseCommand.addChild(debugCommand);
|
||||
baseCommand.addChild(pauseCommand);
|
||||
baseCommand.addChild(resumeCommand);
|
||||
baseCommand.addChild(renderCommand);
|
||||
renderCommand.addChild(prioRenderCommand);
|
||||
renderCommand.addChild(cancelRenderCommand);
|
||||
}
|
||||
|
||||
private Predicate<S> requirements(String permission){
|
||||
return s -> {
|
||||
CommandSource source = commandSourceInterface.apply(s);
|
||||
return plugin.isLoaded() && source.hasPermission(permission);
|
||||
};
|
||||
}
|
||||
|
||||
private Predicate<S> requirementsUnloaded(String permission){
|
||||
return s -> {
|
||||
CommandSource source = commandSourceInterface.apply(s);
|
||||
return source.hasPermission(permission);
|
||||
};
|
||||
}
|
||||
|
||||
private LiteralArgumentBuilder<S> literal(String name){
|
||||
return LiteralArgumentBuilder.<S>literal(name);
|
||||
}
|
||||
|
||||
private <T> RequiredArgumentBuilder<S, T> argument(String name, ArgumentType<T> type){
|
||||
return RequiredArgumentBuilder.<S, T>argument(name, type);
|
||||
}
|
||||
|
||||
private <T> Optional<T> getOptionalArgument(CommandContext<S> context, String argumentName, Class<T> type) {
|
||||
try {
|
||||
return Optional.of(context.getArgument(argumentName, type));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
private Optional<World> parseWorld(String worldName) {
|
||||
for (World world : plugin.getWorlds()) {
|
||||
if (world.getName().equalsIgnoreCase(worldName)) {
|
||||
return Optional.of(world);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<MapType> parseMap(String mapId) {
|
||||
for (MapType map : plugin.getMapTypes()) {
|
||||
if (map.getName().equalsIgnoreCase(mapId)) {
|
||||
return Optional.of(map);
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private Optional<UUID> parseUUID(String uuidString) {
|
||||
try {
|
||||
return Optional.of(UUID.fromString(uuidString));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- COMMANDS ---
|
||||
|
||||
public int statusCommand(CommandContext<S> context) {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
source.sendMessages(helper.createStatusMessage());
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int reloadCommand(CommandContext<S> context) {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
source.sendMessage(Text.of(TextColor.GOLD, "Reloading BlueMap..."));
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
plugin.reload();
|
||||
|
||||
if (plugin.isLoaded()) {
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "BlueMap reloaded!"));
|
||||
} else {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Could not load BlueMap! See the console for details!"));
|
||||
}
|
||||
|
||||
} catch (Exception ex) {
|
||||
Logger.global.logError("Failed to reload BlueMap!", ex);
|
||||
|
||||
source.sendMessage(Text.of(TextColor.RED, "There was an error reloading BlueMap! See the console for details!"));
|
||||
}
|
||||
}).start();
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int debugCommand(CommandContext<S> context) throws CommandSyntaxException {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
// parse arguments
|
||||
Optional<String> worldName = getOptionalArgument(context, "world", String.class);
|
||||
Optional<Double> x = getOptionalArgument(context, "x", Double.class);
|
||||
Optional<Double> y = getOptionalArgument(context, "y", Double.class);
|
||||
Optional<Double> z = getOptionalArgument(context, "z", Double.class);
|
||||
|
||||
World world;
|
||||
Vector3d position;
|
||||
|
||||
if (worldName.isPresent() && x.isPresent() && y.isPresent() && z.isPresent()) {
|
||||
world = parseWorld(worldName.get()).orElse(null);
|
||||
position = new Vector3d(x.get(), y.get(), z.get());
|
||||
|
||||
if (world == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There is no ", helper.worldHelperHover(), " with this name: ", TextColor.WHITE, worldName.get()));
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
world = source.getWorld().orElse(null);
|
||||
position = source.getPosition().orElse(null);
|
||||
|
||||
if (world == null || position == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Can't detect a location from this command-source, you'll have to define a world and position!"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// output debug info
|
||||
Vector3i blockPos = position.floor().toInt();
|
||||
Block block = world.getBlock(blockPos);
|
||||
Block blockBelow = world.getBlock(blockPos.add(0, -1, 0));
|
||||
|
||||
String blockIdMeta = "";
|
||||
String blockBelowIdMeta = "";
|
||||
|
||||
if (world instanceof MCAWorld) {
|
||||
try {
|
||||
Chunk chunk = ((MCAWorld) world).getChunk(MCAWorld.blockToChunk(blockPos));
|
||||
if (chunk instanceof ChunkAnvil112) {
|
||||
blockIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos) + ")";
|
||||
blockBelowIdMeta = " (" + ((ChunkAnvil112) chunk).getBlockIdMeta(blockPos.add(0, -1, 0)) + ")";
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
Logger.global.logError("Failed to read chunk for debug!", ex);
|
||||
}
|
||||
}
|
||||
|
||||
source.sendMessages(Lists.newArrayList(
|
||||
Text.of(TextColor.GOLD, "Block at you: ", TextColor.WHITE, block, TextColor.GRAY, blockIdMeta),
|
||||
Text.of(TextColor.GOLD, "Block below you: ", TextColor.WHITE, blockBelow, TextColor.GRAY, blockBelowIdMeta)
|
||||
));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int pauseCommand(CommandContext<S> context) {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
if (plugin.getRenderManager().isRunning()) {
|
||||
plugin.getRenderManager().stop();
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "BlueMap rendering paused!"));
|
||||
return 1;
|
||||
} else {
|
||||
source.sendMessage(Text.of(TextColor.RED, "BlueMap rendering are already paused!"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int resumeCommand(CommandContext<S> context) {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
if (!plugin.getRenderManager().isRunning()) {
|
||||
plugin.getRenderManager().start();
|
||||
source.sendMessage(Text.of(TextColor.GREEN, "BlueMap renders resumed!"));
|
||||
return 1;
|
||||
} else {
|
||||
source.sendMessage(Text.of(TextColor.RED, "BlueMap renders are already running!"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public int renderCommand(CommandContext<S> context) {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
// parse world/map argument
|
||||
Optional<String> worldOrMap = getOptionalArgument(context, "world|map", String.class);
|
||||
World world = null;
|
||||
MapType map = null;
|
||||
if (worldOrMap.isPresent()) {
|
||||
world = parseWorld(worldOrMap.get()).orElse(null);
|
||||
|
||||
if (world == null) {
|
||||
map = parseMap(worldOrMap.get()).orElse(null);
|
||||
|
||||
if (map == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "There is no ", helper.worldHelperHover(), " or ", helper.mapHelperHover(), " with this name: ", TextColor.WHITE, worldOrMap.get()));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
world = source.getWorld().orElse(null);
|
||||
|
||||
if (world == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Can't detect a world from this command-source, you'll have to define a world or a map to render!").setHoverText(Text.of(TextColor.GRAY, "/bluemap render <world|map>")));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// parse radius and center arguments
|
||||
int radius = getOptionalArgument(context, "radius", Integer.class).orElse(-1);
|
||||
Vector2i center = null;
|
||||
if (radius >= 0) {
|
||||
Optional<Double> x = getOptionalArgument(context, "x", Double.class);
|
||||
Optional<Double> z = getOptionalArgument(context, "z", Double.class);
|
||||
|
||||
if (x.isPresent() && z.isPresent()) {
|
||||
center = new Vector2i(x.get(), z.get());
|
||||
} else {
|
||||
Vector3d position = source.getPosition().orElse(null);
|
||||
if (position == null) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Can't detect a position from this command-source, you'll have to define x,z coordinates to render with a radius!").setHoverText(Text.of(TextColor.GRAY, "/bluemap render <x> <z> " + radius)));
|
||||
return 0;
|
||||
}
|
||||
|
||||
center = position.toVector2(true).floor().toInt();
|
||||
}
|
||||
}
|
||||
|
||||
// execute render
|
||||
if (world != null) {
|
||||
helper.createWorldRenderTask(source, world, center, radius);
|
||||
} else {
|
||||
helper.createMapRenderTask(source, map, center, radius);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
public int prioritizeRenderTaskCommand(CommandContext<S> context) {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
String uuidString = context.getArgument("uuid", String.class);
|
||||
Optional<UUID> taskUUID = parseUUID(uuidString);
|
||||
if (!taskUUID.isPresent()) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Not a valid UUID: " + uuidString));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (RenderTask task : plugin.getRenderManager().getRenderTasks()) {
|
||||
if (task.getUuid().equals(taskUUID.get())) {
|
||||
plugin.getRenderManager().prioritizeRenderTask(task);
|
||||
|
||||
source.sendMessages(helper.createStatusMessage());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
source.sendMessage(Text.of(TextColor.RED, "There is no render-task with this UUID: " + uuidString));
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int cancelRenderTaskCommand(CommandContext<S> context) {
|
||||
CommandSource source = commandSourceInterface.apply(context.getSource());
|
||||
|
||||
String uuidString = context.getArgument("uuid", String.class);
|
||||
Optional<UUID> taskUUID = parseUUID(uuidString);
|
||||
if (!taskUUID.isPresent()) {
|
||||
source.sendMessage(Text.of(TextColor.RED, "Not a valid UUID: " + uuidString));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (RenderTask task : plugin.getRenderManager().getRenderTasks()) {
|
||||
if (task.getUuid().equals(taskUUID.get())) {
|
||||
plugin.getRenderManager().removeRenderTask(task);
|
||||
|
||||
source.sendMessages(helper.createStatusMessage());
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
source.sendMessage(Text.of(TextColor.RED, "There is no render-task with this UUID: " + uuidString));
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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 de.bluecolored.bluemap.common.plugin.commands;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import de.bluecolored.bluemap.common.MapType;
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
|
||||
public class MapSuggestionProvider<S> extends AbstractSuggestionProvider<S> {
|
||||
|
||||
private Plugin plugin;
|
||||
|
||||
public MapSuggestionProvider(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPossibleValues() {
|
||||
Collection<String> values = new HashSet<>();
|
||||
|
||||
for (MapType map : plugin.getMapTypes()) {
|
||||
values.add(map.getId());
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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 de.bluecolored.bluemap.common.plugin.commands;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import de.bluecolored.bluemap.common.MapType;
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
public class WorldOrMapSuggestionProvider<S> extends AbstractSuggestionProvider<S> {
|
||||
|
||||
private Plugin plugin;
|
||||
|
||||
public WorldOrMapSuggestionProvider(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPossibleValues() {
|
||||
Collection<String> values = new HashSet<>();
|
||||
|
||||
for (World world : plugin.getWorlds()) {
|
||||
values.add(world.getName());
|
||||
}
|
||||
|
||||
for (MapType map : plugin.getMapTypes()) {
|
||||
values.add(map.getId());
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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 de.bluecolored.bluemap.common.plugin.commands;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
public class WorldSuggestionProvider<S> extends AbstractSuggestionProvider<S> {
|
||||
|
||||
private Plugin plugin;
|
||||
|
||||
public WorldSuggestionProvider(Plugin plugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getPossibleValues() {
|
||||
Collection<String> values = new HashSet<>();
|
||||
|
||||
for (World world : plugin.getWorlds()) {
|
||||
values.add(world.getName());
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
}
|
@ -24,7 +24,12 @@
|
||||
*/
|
||||
package de.bluecolored.bluemap.common.plugin.serverinterface;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3d;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
public interface CommandSource {
|
||||
|
||||
@ -36,4 +41,14 @@ default void sendMessages(Iterable<Text> textLines) {
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasPermission(String permission);
|
||||
|
||||
default Optional<World> getWorld() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
default Optional<Vector3d> getPosition() {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ dependencies {
|
||||
exclude group: 'com.google.code.gson', module: 'gson'
|
||||
exclude group: 'org.apache.commons', module: 'commons-lang3'
|
||||
exclude group: 'commons-io', module: 'commons-io'
|
||||
exclude group: 'com.mojang', module: 'brigadier'
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,4 +41,9 @@ public void sendMessage(Text text) {
|
||||
delegate.sendFeedback(ITextComponent.Serializer.fromJson(text.toJSONString()), false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return delegate.hasPermissionLevel(1);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,231 +0,0 @@
|
||||
/*
|
||||
* This file is part of BlueMap, licensed under the MIT License (MIT).
|
||||
*
|
||||
* Copyright (c) Blue (Lukas Rieger) <https://bluecolored.de>
|
||||
* Copyright (c) contributors
|
||||
*
|
||||
* 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 de.bluecolored.bluemap.forge;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.flowpowered.math.vector.Vector2i;
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.LiteralMessage;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Commands;
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.common.plugin.text.TextColor;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.server.permission.DefaultPermissionLevel;
|
||||
import net.minecraftforge.server.permission.PermissionAPI;
|
||||
|
||||
public class ForgeCommands {
|
||||
|
||||
private ForgeMod mod;
|
||||
private Commands commands;
|
||||
|
||||
public ForgeCommands(ForgeMod mod, Plugin bluemap) {
|
||||
this.mod = mod;
|
||||
this.commands = bluemap.getCommands();
|
||||
}
|
||||
|
||||
public void registerCommands(CommandDispatcher<CommandSource> dispatcher) {
|
||||
LiteralArgumentBuilder<CommandSource> base = literal("bluemap");
|
||||
|
||||
PermissionAPI.registerNode("bluemap.status", DefaultPermissionLevel.OP, "Permission for using /bluemap");
|
||||
base.executes(c -> {
|
||||
if (!checkPermission(c, "bluemap.status")) return 0;
|
||||
|
||||
commands.executeRootCommand(new ForgeCommandSource(c.getSource()));
|
||||
return 1;
|
||||
});
|
||||
|
||||
PermissionAPI.registerNode("bluemap.reload", DefaultPermissionLevel.OP, "Permission for using /bluemap reload");
|
||||
base.then(literal("reload").executes(c -> {
|
||||
if (!checkPermission(c, "bluemap.reload")) return 0;
|
||||
|
||||
commands.executeReloadCommand(new ForgeCommandSource(c.getSource()));
|
||||
return 1;
|
||||
}));
|
||||
|
||||
PermissionAPI.registerNode("bluemap.pause", DefaultPermissionLevel.OP, "Permission for using /bluemap pause");
|
||||
base.then(literal("pause").executes(c -> {
|
||||
if (!checkPermission(c, "bluemap.pause")) return 0;
|
||||
|
||||
commands.executePauseCommand(new ForgeCommandSource(c.getSource()));
|
||||
return 1;
|
||||
}));
|
||||
|
||||
PermissionAPI.registerNode("bluemap.resume", DefaultPermissionLevel.OP, "Permission for using /bluemap resume");
|
||||
base.then(literal("resume").executes(c -> {
|
||||
if (!checkPermission(c, "bluemap.resume")) return 0;
|
||||
|
||||
commands.executeResumeCommand(new ForgeCommandSource(c.getSource()));
|
||||
return 1;
|
||||
}));
|
||||
|
||||
PermissionAPI.registerNode("bluemap.render", DefaultPermissionLevel.OP, "Permission for using /bluemap render");
|
||||
Command<CommandSource> renderCommand = c -> {
|
||||
if (!checkPermission(c, "bluemap.render")) return 0;
|
||||
|
||||
String worldName = null;
|
||||
try {
|
||||
worldName = c.getArgument("world", String.class);
|
||||
} catch (IllegalArgumentException ex) {}
|
||||
|
||||
int blockRadius = -1;
|
||||
try {
|
||||
blockRadius = c.getArgument("block-radius", Integer.class);
|
||||
} catch (IllegalArgumentException ex) {}
|
||||
|
||||
PlayerEntity player = null;
|
||||
try {
|
||||
player = c.getSource().asPlayer();
|
||||
} catch (CommandSyntaxException ex) {}
|
||||
|
||||
if (player == null && blockRadius != -1) {
|
||||
throw new SimpleCommandExceptionType(new LiteralMessage("You can only use a block-radius if you are a player!")).create();
|
||||
}
|
||||
|
||||
if (worldName == null) {
|
||||
if (player == null) throw new SimpleCommandExceptionType(new LiteralMessage("You need to define a world! (/bluemap render <world>)")).create();
|
||||
Vector2i center = new Vector2i(player.getPosition().getX(), player.getPosition().getZ());
|
||||
|
||||
UUID world;
|
||||
try {
|
||||
world = mod.getUUIDForWorld((ServerWorld) player.getEntityWorld());
|
||||
} catch (IOException ex) {
|
||||
throw new SimpleCommandExceptionType(new LiteralMessage("Could not detect the world you are currently in, try to define a world using /bluemap render <world>")).create();
|
||||
}
|
||||
|
||||
return commands.executeRenderWorldCommand(new ForgeCommandSource(c.getSource()), world, center, blockRadius) ? 1 : 0;
|
||||
} else {
|
||||
if (player == null) {
|
||||
return commands.executeRenderCommand(new ForgeCommandSource(c.getSource()), worldName) ? 1 : 0;
|
||||
} else {
|
||||
Vector2i center = new Vector2i(player.getPosition().getX(), player.getPosition().getZ());
|
||||
return commands.executeRenderCommand(new ForgeCommandSource(c.getSource()), worldName, center, blockRadius) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
base.then(literal("render")
|
||||
.executes(renderCommand)
|
||||
.then(argument("block-radius", IntegerArgumentType.integer(0)).executes(renderCommand))
|
||||
.then(argument("world", StringArgumentType.word())
|
||||
.executes(renderCommand)
|
||||
.then(argument("block-radius", IntegerArgumentType.integer(0))).executes(renderCommand)
|
||||
)
|
||||
|
||||
.then(literal("prioritize").then(argument("task-uuid", StringArgumentType.word()).executes(c -> {
|
||||
if (!checkPermission(c, "bluemap.render")) return 0;
|
||||
|
||||
try {
|
||||
UUID taskUUID = UUID.fromString(c.getArgument("task-uuid", String.class));
|
||||
commands.executePrioritizeRenderTaskCommand(new ForgeCommandSource(c.getSource()), taskUUID);
|
||||
return 1;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new SimpleCommandExceptionType(new LiteralMessage("Invalid task-uuid!")).create();
|
||||
}
|
||||
})))
|
||||
|
||||
.then(literal("remove").then(argument("task-uuid", StringArgumentType.word()).executes(c -> {
|
||||
if (!checkPermission(c, "bluemap.render")) return 0;
|
||||
|
||||
try {
|
||||
UUID taskUUID = UUID.fromString(c.getArgument("task-uuid", String.class));
|
||||
commands.executeRemoveRenderTaskCommand(new ForgeCommandSource(c.getSource()), taskUUID);
|
||||
return 1;
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new SimpleCommandExceptionType(new LiteralMessage("Invalid task-uuid!")).create();
|
||||
}
|
||||
})))
|
||||
);
|
||||
|
||||
PermissionAPI.registerNode("bluemap.debug", DefaultPermissionLevel.OP, "Permission for using /bluemap debug");
|
||||
base.then(literal("debug").executes(c -> {
|
||||
if (!checkPermission(c, "bluemap.debug")) return 0;
|
||||
|
||||
Entity entity = c.getSource().assertIsEntity();
|
||||
BlockPos mcPos = entity.getPosition();
|
||||
Vector3i pos = new Vector3i(mcPos.getX(), mcPos.getY(), mcPos.getZ());
|
||||
|
||||
UUID world;
|
||||
try {
|
||||
world = mod.getUUIDForWorld((ServerWorld) entity.getEntityWorld());
|
||||
} catch (IOException e) {
|
||||
throw new SimpleCommandExceptionType(new LiteralMessage("Could not detect the world you are currently in!")).create();
|
||||
}
|
||||
|
||||
commands.executeDebugCommand(new ForgeCommandSource(c.getSource()), world, pos);
|
||||
return 1;
|
||||
}));
|
||||
|
||||
dispatcher.register(base);
|
||||
}
|
||||
|
||||
private boolean checkPermission(CommandContext<CommandSource> command, String permission) {
|
||||
ForgeCommandSource cs = new ForgeCommandSource(command.getSource());
|
||||
|
||||
boolean hasPermission = false;
|
||||
try {
|
||||
if (PermissionAPI.hasPermission(command.getSource().asPlayer(), permission)) {
|
||||
hasPermission = true;
|
||||
}
|
||||
} catch (CommandSyntaxException ex) {
|
||||
if (command.getSource().hasPermissionLevel(1)) {
|
||||
hasPermission = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasPermission) {
|
||||
cs.sendMessage(Text.of(TextColor.RED, "You don't have the permissions to use this command!"));
|
||||
}
|
||||
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
public static LiteralArgumentBuilder<CommandSource> literal(String name){
|
||||
return LiteralArgumentBuilder.<CommandSource>literal(name);
|
||||
}
|
||||
|
||||
public static <S extends CommandSource, T> RequiredArgumentBuilder<S, T> argument(String name, ArgumentType<T> type){
|
||||
return RequiredArgumentBuilder.<S, T>argument(name, type);
|
||||
}
|
||||
|
||||
}
|
@ -37,9 +37,11 @@
|
||||
import com.flowpowered.math.vector.Vector3i;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.common.plugin.commands.Commands;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import net.minecraft.command.CommandSource;
|
||||
import net.minecraft.world.server.ServerWorld;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.world.BlockEvent;
|
||||
@ -53,7 +55,7 @@
|
||||
public class ForgeMod implements ServerInterface {
|
||||
|
||||
private Plugin bluemap;
|
||||
private ForgeCommands commands;
|
||||
private Commands<CommandSource> commands;
|
||||
private Map<String, UUID> worldUUIDs;
|
||||
private Collection<ServerEventListener> eventListeners;
|
||||
|
||||
@ -61,7 +63,6 @@ public ForgeMod() {
|
||||
Logger.global = new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME));
|
||||
|
||||
this.bluemap = new Plugin("forge", this);
|
||||
this.commands = new ForgeCommands(this, bluemap);
|
||||
this.worldUUIDs = new HashMap<>();
|
||||
this.eventListeners = new ArrayList<>(1);
|
||||
|
||||
@ -86,7 +87,8 @@ public void onServerStarting(FMLServerStartingEvent event) {
|
||||
}
|
||||
}
|
||||
|
||||
this.commands.registerCommands(event.getCommandDispatcher());
|
||||
//register commands
|
||||
this.commands = new Commands<>(bluemap, event.getCommandDispatcher(), ForgeCommandSource::new);
|
||||
|
||||
new Thread(() -> {
|
||||
try {
|
||||
@ -202,4 +204,8 @@ public File getConfigFolder() {
|
||||
return new File("config/bluemap");
|
||||
}
|
||||
|
||||
public Commands<CommandSource> getCommands() {
|
||||
return commands;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ build.dependsOn shadowJar {
|
||||
|
||||
relocate 'net.querz.nbt', 'de.bluecolored.shadow.querz.nbt'
|
||||
relocate 'org.apache.commons.io', 'de.bluecolored.shadow.apache.commons.io'
|
||||
relocate 'com.mojang.brigadier', 'de.bluecolored.shadow.mojang.brigadier'
|
||||
|
||||
minimize()
|
||||
}
|
||||
|
@ -24,16 +24,25 @@
|
||||
*/
|
||||
package de.bluecolored.bluemap.sponge;
|
||||
|
||||
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.spongepowered.api.text.serializer.TextSerializers;
|
||||
import org.spongepowered.api.world.Locatable;
|
||||
|
||||
import com.flowpowered.math.vector.Vector3d;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||
import de.bluecolored.bluemap.core.world.World;
|
||||
|
||||
public class SpongeCommandSource implements CommandSource {
|
||||
|
||||
private Plugin plugin;
|
||||
private org.spongepowered.api.command.CommandSource delegate;
|
||||
|
||||
public SpongeCommandSource(org.spongepowered.api.command.CommandSource delegate) {
|
||||
public SpongeCommandSource(Plugin plugin, org.spongepowered.api.command.CommandSource delegate) {
|
||||
this.plugin = plugin;
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@ -43,4 +52,27 @@ public void sendMessage(Text text) {
|
||||
delegate.sendMessage(spongeText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission) {
|
||||
return delegate.hasPermission(permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Vector3d> getPosition() {
|
||||
if (delegate instanceof Locatable) {
|
||||
return Optional.of(((Locatable) delegate).getLocation().getPosition());
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<World> getWorld() {
|
||||
if (delegate instanceof Locatable) {
|
||||
return Optional.ofNullable(plugin.getWorld(((Locatable) delegate).getLocation().getExtent().getUniqueId()));
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,194 +24,136 @@
|
||||
*/
|
||||
package de.bluecolored.bluemap.sponge;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.spongepowered.api.command.CommandCallable;
|
||||
import org.spongepowered.api.command.CommandException;
|
||||
import org.spongepowered.api.command.CommandResult;
|
||||
import org.spongepowered.api.command.args.GenericArguments;
|
||||
import org.spongepowered.api.command.spec.CommandSpec;
|
||||
import org.spongepowered.api.command.CommandSource;
|
||||
import org.spongepowered.api.text.Text;
|
||||
import org.spongepowered.api.text.format.TextColors;
|
||||
import org.spongepowered.api.world.Locatable;
|
||||
import org.spongepowered.api.world.Location;
|
||||
import org.spongepowered.api.world.storage.WorldProperties;
|
||||
import org.spongepowered.api.world.World;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Commands;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import com.mojang.brigadier.tree.CommandNode;
|
||||
|
||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||
import de.bluecolored.bluemap.common.plugin.commands.Commands;
|
||||
|
||||
public class SpongeCommands {
|
||||
|
||||
private Commands commands;
|
||||
private CommandDispatcher<CommandSource> dispatcher;
|
||||
|
||||
public SpongeCommands(Commands commands) {
|
||||
this.commands = commands;
|
||||
public SpongeCommands(final Plugin plugin) {
|
||||
this.dispatcher = new CommandDispatcher<>();
|
||||
|
||||
// register commands
|
||||
new Commands<>(plugin, dispatcher, bukkitSender -> new SpongeCommandSource(plugin, bukkitSender));
|
||||
}
|
||||
|
||||
public CommandSpec createRootCommand() {
|
||||
return CommandSpec.builder()
|
||||
.description(Text.of("Displays BlueMaps render status"))
|
||||
.permission("bluemap.status")
|
||||
.childArgumentParseExceptionFallback(false)
|
||||
.child(createReloadCommand(), "reload")
|
||||
.child(createPauseRenderCommand(), "pause")
|
||||
.child(createResumeRenderCommand(), "resume")
|
||||
.child(createRenderCommand(), "render")
|
||||
.child(createDebugCommand(), "debug")
|
||||
.executor((source, args) -> {
|
||||
commands.executeRootCommand(new SpongeCommandSource(source));
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
public Collection<SpongeCommandProxy> getRootCommands(){
|
||||
Collection<SpongeCommandProxy> rootCommands = new ArrayList<>();
|
||||
|
||||
for (CommandNode<CommandSource> node : this.dispatcher.getRoot().getChildren()) {
|
||||
rootCommands.add(new SpongeCommandProxy(node.getName()));
|
||||
}
|
||||
|
||||
return rootCommands;
|
||||
}
|
||||
|
||||
public CommandSpec createReloadCommand() {
|
||||
return CommandSpec.builder()
|
||||
.description(Text.of("Reloads all resources and configuration-files"))
|
||||
.permission("bluemap.reload")
|
||||
.executor((source, args) -> {
|
||||
commands.executeReloadCommand(new SpongeCommandSource(source));
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
public class SpongeCommandProxy implements CommandCallable {
|
||||
|
||||
public CommandSpec createPauseRenderCommand() {
|
||||
return CommandSpec.builder()
|
||||
.description(Text.of("Pauses all rendering"))
|
||||
.permission("bluemap.pause")
|
||||
.executor((source, args) -> {
|
||||
if (commands.executePauseCommand(new SpongeCommandSource(source))) {
|
||||
return CommandResult.success();
|
||||
} else {
|
||||
return CommandResult.empty();
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
private String label;
|
||||
|
||||
public CommandSpec createResumeRenderCommand() {
|
||||
return CommandSpec.builder()
|
||||
.description(Text.of("Resumes all paused rendering"))
|
||||
.permission("bluemap.resume")
|
||||
.executor((source, args) -> {
|
||||
if (commands.executeResumeCommand(new SpongeCommandSource(source))) {
|
||||
return CommandResult.success();
|
||||
} else {
|
||||
return CommandResult.empty();
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
protected SpongeCommandProxy(String label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
public CommandSpec createRenderCommand() {
|
||||
return CommandSpec.builder()
|
||||
.description(Text.of("Renders the whole world"))
|
||||
.permission("bluemap.render")
|
||||
.childArgumentParseExceptionFallback(false)
|
||||
.child(createPrioritizeTaskCommand(), "prioritize")
|
||||
.child(createRemoveTaskCommand(), "remove")
|
||||
.arguments(
|
||||
GenericArguments.optionalWeak(GenericArguments.onlyOne(GenericArguments.world(Text.of("world")))),
|
||||
GenericArguments.optional(GenericArguments.integer(Text.of("block-radius")))
|
||||
)
|
||||
.executor((source, args) -> {
|
||||
WorldProperties spongeWorld = args.<WorldProperties>getOne("world").orElse(null);
|
||||
@Override
|
||||
public CommandResult process(CommandSource source, String arguments) throws CommandException {
|
||||
String command = label;
|
||||
if (!arguments.isEmpty()) {
|
||||
command += " " + arguments;
|
||||
}
|
||||
|
||||
if (spongeWorld == null && source instanceof Locatable) {
|
||||
Location<org.spongepowered.api.world.World> loc = ((Locatable) source).getLocation();
|
||||
spongeWorld = loc.getExtent().getProperties();
|
||||
}
|
||||
try {
|
||||
return CommandResult.successCount(dispatcher.execute(command, source));
|
||||
} catch (CommandSyntaxException ex) {
|
||||
source.sendMessage(Text.of(TextColors.RED, ex.getRawMessage().getString()));
|
||||
|
||||
if (spongeWorld == null){
|
||||
source.sendMessage(Text.of(TextColors.RED, "You have to define a world to render!"));
|
||||
return CommandResult.empty();
|
||||
}
|
||||
String context = ex.getContext();
|
||||
if (context != null) source.sendMessage(Text.of(TextColors.GRAY, context));
|
||||
|
||||
int radius = args.<Integer>getOne("block-radius").orElse(-1);
|
||||
|
||||
if (radius >= 0) {
|
||||
if (source instanceof Locatable) {
|
||||
Location<org.spongepowered.api.world.World> loc = ((Locatable) source).getLocation();
|
||||
|
||||
if (commands.executeRenderWorldCommand(new SpongeCommandSource(source), spongeWorld.getUniqueId(), loc.getBlockPosition().toVector2(true), radius)) {
|
||||
return CommandResult.success();
|
||||
} else {
|
||||
return CommandResult.empty();
|
||||
}
|
||||
} else {
|
||||
source.sendMessages(
|
||||
Text.of(TextColors.RED, "Could not determine a center-location for the radius!"),
|
||||
Text.of(TextColors.GRAY, "Could not determine a center-location for the radius!")
|
||||
);
|
||||
return CommandResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
if (commands.executeRenderWorldCommand(new SpongeCommandSource(source), spongeWorld.getUniqueId())) {
|
||||
return CommandResult.success();
|
||||
} else {
|
||||
return CommandResult.empty();
|
||||
}
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public CommandSpec createPrioritizeTaskCommand() {
|
||||
return CommandSpec.builder()
|
||||
.description(Text.of("Prioritizes the render-task with the given uuid"))
|
||||
.permission("bluemap.render")
|
||||
.arguments(GenericArguments.uuid(Text.of("task-uuid")))
|
||||
.executor((source, args) -> {
|
||||
Optional<UUID> uuid = args.<UUID>getOne("task-uuid");
|
||||
if (!uuid.isPresent()) {
|
||||
source.sendMessage(Text.of(TextColors.RED, "You need to specify a task-uuid"));
|
||||
return CommandResult.empty();
|
||||
}
|
||||
|
||||
commands.executePrioritizeRenderTaskCommand(new SpongeCommandSource(source), uuid.get());
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public CommandSpec createRemoveTaskCommand() {
|
||||
return CommandSpec.builder()
|
||||
.description(Text.of("Removes the render-task with the given uuid"))
|
||||
.permission("bluemap.render")
|
||||
.arguments(GenericArguments.uuid(Text.of("task-uuid")))
|
||||
.executor((source, args) -> {
|
||||
Optional<UUID> uuid = args.<UUID>getOne("task-uuid");
|
||||
if (!uuid.isPresent()) {
|
||||
source.sendMessage(Text.of(TextColors.RED, "You need to specify a task-uuid"));
|
||||
return CommandResult.empty();
|
||||
}
|
||||
|
||||
commands.executeRemoveRenderTaskCommand(new SpongeCommandSource(source), uuid.get());
|
||||
return CommandResult.success();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
|
||||
public CommandSpec createDebugCommand() {
|
||||
return CommandSpec.builder()
|
||||
.permission("bluemap.debug")
|
||||
.description(Text.of("Prints some debug info"))
|
||||
.extendedDescription(Text.of("Prints some information about how bluemap sees the blocks at and below your position"))
|
||||
.executor((source, args) -> {
|
||||
if (source instanceof Locatable) {
|
||||
Location<org.spongepowered.api.world.World> loc = ((Locatable) source).getLocation();
|
||||
UUID worldUuid = loc.getExtent().getUniqueId();
|
||||
|
||||
if (commands.executeDebugCommand(new SpongeCommandSource(source), worldUuid, loc.getBlockPosition())) {
|
||||
return CommandResult.success();
|
||||
} else {
|
||||
return CommandResult.empty();
|
||||
}
|
||||
}
|
||||
|
||||
source.sendMessage(Text.of(TextColors.RED, "You can only execute this command as a player!"));
|
||||
return CommandResult.empty();
|
||||
})
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSuggestions(CommandSource source, String arguments, Location<World> targetPosition) throws CommandException {
|
||||
String command = label;
|
||||
if (!arguments.isEmpty()) {
|
||||
command += " " + arguments;
|
||||
}
|
||||
|
||||
List<String> completions = new ArrayList<>();
|
||||
|
||||
try {
|
||||
Suggestions suggestions = dispatcher.getCompletionSuggestions(dispatcher.parse(command, source)).get(100, TimeUnit.MILLISECONDS);
|
||||
for (Suggestion suggestion : suggestions.getList()) {
|
||||
String text = suggestion.getText();
|
||||
|
||||
if (text.indexOf(' ') == -1) {
|
||||
completions.add(text);
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException ignore) {}
|
||||
|
||||
completions.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
|
||||
return completions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean testPermission(CommandSource source) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Text> getShortDescription(CommandSource source) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Text> getHelp(CommandSource source) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Text getUsage(CommandSource source) {
|
||||
CommandNode<CommandSource> node = dispatcher.getRoot().getChild(label);
|
||||
if (node == null) return Text.of("/" + label);
|
||||
|
||||
List<Text> lines = new ArrayList<>();
|
||||
for (String usageString : dispatcher.getSmartUsage(node, source).values()) {
|
||||
lines.add(Text.of(TextColors.WHITE, "/", TextColors.GRAY, usageString));
|
||||
}
|
||||
|
||||
return Text.joinWith(Text.NEW_LINE, lines);
|
||||
}
|
||||
|
||||
public String getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -45,6 +45,7 @@
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerEventListener;
|
||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
||||
import de.bluecolored.bluemap.core.logger.Logger;
|
||||
import de.bluecolored.bluemap.sponge.SpongeCommands.SpongeCommandProxy;
|
||||
import net.querz.nbt.CompoundTag;
|
||||
import net.querz.nbt.NBTUtil;
|
||||
|
||||
@ -65,6 +66,7 @@ public class SpongePlugin implements ServerInterface {
|
||||
private MetricsLite2 metrics;
|
||||
|
||||
private Plugin bluemap;
|
||||
private SpongeCommands commands;
|
||||
|
||||
private SpongeExecutorService asyncExecutor;
|
||||
|
||||
@ -73,6 +75,7 @@ public SpongePlugin(org.slf4j.Logger logger) {
|
||||
Logger.global = new Slf4jLogger(logger);
|
||||
|
||||
this.bluemap = new Plugin("sponge", this);
|
||||
this.commands = new SpongeCommands(bluemap);
|
||||
}
|
||||
|
||||
@Listener
|
||||
@ -84,7 +87,10 @@ public void onServerStart(GameStartingServerEvent evt) {
|
||||
Sponge.getServer().saveWorldProperties(properties);
|
||||
}
|
||||
|
||||
Sponge.getCommandManager().register(this, new SpongeCommands(bluemap.getCommands()).createRootCommand(), "bluemap");
|
||||
//register commands
|
||||
for(SpongeCommandProxy command : commands.getRootCommands()) {
|
||||
Sponge.getCommandManager().register(this, command, command.getLabel());
|
||||
}
|
||||
|
||||
asyncExecutor.execute(() -> {
|
||||
try {
|
||||
|
@ -21,6 +21,9 @@ allprojects {
|
||||
maven {
|
||||
url = 'https://files.minecraftforge.net/maven/'
|
||||
}
|
||||
maven {
|
||||
url "https://libraries.minecraft.net"
|
||||
}
|
||||
}
|
||||
|
||||
compileJava.options.compilerArgs.add '-parameters'
|
||||
|
Loading…
Reference in New Issue
Block a user