mirror of
https://github.com/BlueMap-Minecraft/BlueMap.git
synced 2024-11-25 20:16:00 +01:00
Merge branch 'mc/1.13'
This commit is contained in:
commit
95afba305f
@ -1,4 +1,4 @@
|
|||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/'
|
url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/'
|
||||||
|
|
||||||
@ -31,6 +31,7 @@ build.dependsOn shadowJar {
|
|||||||
relocate 'org.apache.commons.io', 'de.bluecolored.shadow.apache.commons.io'
|
relocate 'org.apache.commons.io', 'de.bluecolored.shadow.apache.commons.io'
|
||||||
relocate 'org.apache.commons.lang3', 'de.bluecolored.shadow.apache.commons.lang3'
|
relocate 'org.apache.commons.lang3', 'de.bluecolored.shadow.apache.commons.lang3'
|
||||||
relocate 'org.bstats.bukkit', 'de.bluecolored.shadow.bstats.bukkit'
|
relocate 'org.bstats.bukkit', 'de.bluecolored.shadow.bstats.bukkit'
|
||||||
|
relocate 'com.mojang.brigadier', 'de.bluecolored.shadow.mojang.brigadier'
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
@ -24,18 +24,29 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.bukkit;
|
package de.bluecolored.bluemap.bukkit;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.command.BlockCommandSender;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
import org.bukkit.entity.Entity;
|
||||||
import org.bukkit.entity.Player;
|
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.serverinterface.CommandSource;
|
||||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||||
|
import de.bluecolored.bluemap.core.world.World;
|
||||||
|
|
||||||
public class BukkitCommandSource implements CommandSource {
|
public class BukkitCommandSource implements CommandSource {
|
||||||
|
|
||||||
|
private Plugin plugin;
|
||||||
private CommandSender delegate;
|
private CommandSender delegate;
|
||||||
|
|
||||||
public BukkitCommandSource(CommandSender delegate) {
|
public BukkitCommandSource(Plugin plugin, CommandSender delegate) {
|
||||||
|
this.plugin = plugin;
|
||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,5 +64,44 @@ public void sendMessage(Text text) {
|
|||||||
delegate.sendMessage(text.toPlainString());
|
delegate.sendMessage(text.toPlainString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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;
|
package de.bluecolored.bluemap.bukkit;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
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.apache.commons.lang.StringUtils;
|
||||||
import org.bukkit.World;
|
import org.bukkit.ChatColor;
|
||||||
import org.bukkit.command.CommandExecutor;
|
|
||||||
import org.bukkit.command.CommandSender;
|
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.mojang.brigadier.CommandDispatcher;
|
||||||
import com.flowpowered.math.vector.Vector3i;
|
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.Plugin;
|
||||||
import de.bluecolored.bluemap.common.plugin.serverinterface.CommandSource;
|
import de.bluecolored.bluemap.common.plugin.commands.Commands;
|
||||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
|
||||||
import de.bluecolored.bluemap.common.plugin.text.TextColor;
|
|
||||||
|
|
||||||
public class BukkitCommands implements CommandExecutor {
|
public class BukkitCommands implements Listener {
|
||||||
|
|
||||||
|
private CommandDispatcher<CommandSender> dispatcher;
|
||||||
|
|
||||||
private Commands bluemapCommands;
|
public BukkitCommands(final Plugin plugin) {
|
||||||
|
this.dispatcher = new CommandDispatcher<>();
|
||||||
private Collection<Command> commands;
|
|
||||||
|
// register commands
|
||||||
public BukkitCommands(Commands commands) {
|
new Commands<>(plugin, dispatcher, bukkitSender -> new BukkitCommandSource(plugin, bukkitSender));
|
||||||
this.bluemapCommands = commands;
|
|
||||||
this.commands = new ArrayList<>();
|
|
||||||
initCommands();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initCommands() {
|
public Collection<BukkitCommand> getRootCommands(){
|
||||||
|
Collection<BukkitCommand> rootCommands = new ArrayList<>();
|
||||||
|
|
||||||
commands.add(new Command("bluemap.status") {
|
for (CommandNode<CommandSender> node : this.dispatcher.getRoot().getChildren()) {
|
||||||
@Override
|
rootCommands.add(new CommandProxy(node.getName()));
|
||||||
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;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
return rootCommands;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@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();
|
||||||
|
|
||||||
@Override
|
if (text.indexOf(' ') == -1) {
|
||||||
public boolean onCommand(CommandSender sender, org.bukkit.command.Command bukkitCommand, String label, String[] args) {
|
completions.add(text);
|
||||||
int max = -1;
|
}
|
||||||
Command maxCommand = null;
|
|
||||||
for (Command command : commands) {
|
|
||||||
int matchSize = command.matches(args);
|
|
||||||
if (matchSize > max) {
|
|
||||||
maxCommand = command;
|
|
||||||
max = matchSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
private abstract class Command {
|
|
||||||
|
|
||||||
private String[] command;
|
|
||||||
private String permission;
|
|
||||||
|
|
||||||
public Command(String permission, String... command) {
|
|
||||||
this.command = command;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return command.length;
|
if (!completions.isEmpty()) {
|
||||||
|
completions.sort((s1, s2) -> s1.compareToIgnoreCase(s2));
|
||||||
|
evt.setCompletions(completions);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException | ExecutionException | TimeoutException ignore) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CommandProxy extends BukkitCommand {
|
||||||
|
|
||||||
|
protected CommandProxy(String name) {
|
||||||
|
super(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean checkPermission(CommandSender sender) {
|
@Override
|
||||||
if (sender.isOp()) return true;
|
public boolean execute(CommandSender sender, String commandLabel, String[] args) {
|
||||||
return sender.hasPermission(permission);
|
String command = commandLabel;
|
||||||
|
if (args.length > 0) {
|
||||||
|
command += " " + StringUtils.join(args, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return dispatcher.execute(command, sender) > 0;
|
||||||
|
} catch (CommandSyntaxException ex) {
|
||||||
|
sender.sendMessage(ChatColor.RED + ex.getRawMessage().getString());
|
||||||
|
|
||||||
|
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.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
@ -34,6 +35,8 @@
|
|||||||
import org.bstats.bukkit.MetricsLite;
|
import org.bstats.bukkit.MetricsLite;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.World;
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.command.CommandMap;
|
||||||
|
import org.bukkit.command.defaults.BukkitCommand;
|
||||||
import org.bukkit.plugin.java.JavaPlugin;
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
import de.bluecolored.bluemap.common.plugin.Plugin;
|
||||||
@ -54,7 +57,7 @@ public BukkitPlugin() {
|
|||||||
|
|
||||||
this.eventForwarder = new EventForwarder();
|
this.eventForwarder = new EventForwarder();
|
||||||
this.bluemap = new Plugin("bukkit", this);
|
this.bluemap = new Plugin("bukkit", this);
|
||||||
this.commands = new BukkitCommands(bluemap.getCommands());
|
this.commands = new BukkitCommands(this.bluemap);
|
||||||
|
|
||||||
BukkitPlugin.instance = this;
|
BukkitPlugin.instance = this;
|
||||||
}
|
}
|
||||||
@ -69,9 +72,27 @@ public void onEnable() {
|
|||||||
world.save();
|
world.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//register events
|
||||||
getServer().getPluginManager().registerEvents(eventForwarder, this);
|
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, () -> {
|
getServer().getScheduler().runTaskAsynchronously(this, () -> {
|
||||||
try {
|
try {
|
||||||
Logger.global.logInfo("Loading...");
|
Logger.global.logInfo("Loading...");
|
||||||
|
@ -5,17 +5,7 @@ version: ${version}
|
|||||||
author: "Blue (TBlueF / Lukas Rieger)"
|
author: "Blue (TBlueF / Lukas Rieger)"
|
||||||
authors: [Blue (TBlueF / Lukas Rieger)]
|
authors: [Blue (TBlueF / Lukas Rieger)]
|
||||||
website: "https://github.com/BlueMap-Minecraft"
|
website: "https://github.com/BlueMap-Minecraft"
|
||||||
commands:
|
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:
|
permissions:
|
||||||
bluemap.*:
|
bluemap.*:
|
||||||
children:
|
children:
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
|
compile 'com.mojang:brigadier:1.0.17'
|
||||||
|
|
||||||
compile project(':BlueMapCore')
|
compile project(':BlueMapCore')
|
||||||
compile project(':BlueMapAPI')
|
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 String implementationType;
|
||||||
|
|
||||||
private ServerInterface serverInterface;
|
private ServerInterface serverInterface;
|
||||||
private Commands commands;
|
|
||||||
|
|
||||||
private MainConfig config;
|
private MainConfig config;
|
||||||
private ResourcePack resourcePack;
|
private ResourcePack resourcePack;
|
||||||
@ -102,7 +101,6 @@ public Plugin(String implementationType, ServerInterface serverInterface) {
|
|||||||
this.implementationType = implementationType.toLowerCase();
|
this.implementationType = implementationType.toLowerCase();
|
||||||
|
|
||||||
this.serverInterface = serverInterface;
|
this.serverInterface = serverInterface;
|
||||||
this.commands = new Commands(this);
|
|
||||||
|
|
||||||
this.maps = new HashMap<>();
|
this.maps = new HashMap<>();
|
||||||
this.worlds = new HashMap<>();
|
this.worlds = new HashMap<>();
|
||||||
@ -393,10 +391,6 @@ public ServerInterface getServerInterface() {
|
|||||||
return serverInterface;
|
return serverInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Commands getCommands() {
|
|
||||||
return commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
public MainConfig getMainConfig() {
|
public MainConfig getMainConfig() {
|
||||||
return config;
|
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;
|
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.common.plugin.text.Text;
|
||||||
|
import de.bluecolored.bluemap.core.world.World;
|
||||||
|
|
||||||
public interface CommandSource {
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -80,6 +80,7 @@ public HttpResponse handle(HttpRequest request) {
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings ("resource")
|
||||||
private HttpResponse generateResponse(HttpRequest request) {
|
private HttpResponse generateResponse(HttpRequest request) {
|
||||||
String adress = request.getPath();
|
String adress = request.getPath();
|
||||||
if (adress.isEmpty()) adress = "/";
|
if (adress.isEmpty()) adress = "/";
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
package de.bluecolored.bluemap.core.webserver;
|
package de.bluecolored.bluemap.core.webserver;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.Closeable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
@ -39,7 +40,7 @@
|
|||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
public class HttpResponse {
|
public class HttpResponse implements Closeable {
|
||||||
|
|
||||||
private String version;
|
private String version;
|
||||||
private HttpStatusCode statusCode;
|
private HttpStatusCode statusCode;
|
||||||
@ -112,6 +113,11 @@ public void write(OutputStream out) throws IOException {
|
|||||||
data.close();
|
data.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
data.close();
|
||||||
|
}
|
||||||
|
|
||||||
private void writeLine(OutputStreamWriter writer, String line) throws IOException {
|
private void writeLine(OutputStreamWriter writer, String line) throws IOException {
|
||||||
writer.write(line + "\r\n");
|
writer.write(line + "\r\n");
|
||||||
|
@ -28,6 +28,7 @@ dependencies {
|
|||||||
exclude group: 'com.google.code.gson', module: 'gson'
|
exclude group: 'com.google.code.gson', module: 'gson'
|
||||||
exclude group: 'org.apache.commons', module: 'commons-lang3'
|
exclude group: 'org.apache.commons', module: 'commons-lang3'
|
||||||
exclude group: 'commons-io', module: 'commons-io'
|
exclude group: 'commons-io', module: 'commons-io'
|
||||||
|
exclude group: 'com.mojang', module: 'brigadier'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -40,5 +40,10 @@ public ForgeCommandSource(net.minecraft.command.CommandSource delegate) {
|
|||||||
public void sendMessage(Text text) {
|
public void sendMessage(Text text) {
|
||||||
delegate.sendFeedback(ITextComponent.Serializer.fromJson(text.toJSONString()), false);
|
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 com.flowpowered.math.vector.Vector3i;
|
||||||
|
|
||||||
import de.bluecolored.bluemap.common.plugin.Plugin;
|
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.ServerEventListener;
|
||||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
||||||
import de.bluecolored.bluemap.core.logger.Logger;
|
import de.bluecolored.bluemap.core.logger.Logger;
|
||||||
|
import net.minecraft.command.CommandSource;
|
||||||
import net.minecraft.world.server.ServerWorld;
|
import net.minecraft.world.server.ServerWorld;
|
||||||
import net.minecraftforge.common.MinecraftForge;
|
import net.minecraftforge.common.MinecraftForge;
|
||||||
import net.minecraftforge.event.world.BlockEvent;
|
import net.minecraftforge.event.world.BlockEvent;
|
||||||
@ -53,7 +55,7 @@
|
|||||||
public class ForgeMod implements ServerInterface {
|
public class ForgeMod implements ServerInterface {
|
||||||
|
|
||||||
private Plugin bluemap;
|
private Plugin bluemap;
|
||||||
private ForgeCommands commands;
|
private Commands<CommandSource> commands;
|
||||||
private Map<String, UUID> worldUUIDs;
|
private Map<String, UUID> worldUUIDs;
|
||||||
private Collection<ServerEventListener> eventListeners;
|
private Collection<ServerEventListener> eventListeners;
|
||||||
|
|
||||||
@ -61,7 +63,6 @@ public ForgeMod() {
|
|||||||
Logger.global = new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME));
|
Logger.global = new Log4jLogger(LogManager.getLogger(Plugin.PLUGIN_NAME));
|
||||||
|
|
||||||
this.bluemap = new Plugin("forge", this);
|
this.bluemap = new Plugin("forge", this);
|
||||||
this.commands = new ForgeCommands(this, bluemap);
|
|
||||||
this.worldUUIDs = new HashMap<>();
|
this.worldUUIDs = new HashMap<>();
|
||||||
this.eventListeners = new ArrayList<>(1);
|
this.eventListeners = new ArrayList<>(1);
|
||||||
|
|
||||||
@ -85,8 +86,9 @@ public void onServerStarting(FMLServerStartingEvent event) {
|
|||||||
Logger.global.logError("Failed to save world: " + world.getProviderName(), t);
|
Logger.global.logError("Failed to save world: " + world.getProviderName(), t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.commands.registerCommands(event.getCommandDispatcher());
|
//register commands
|
||||||
|
this.commands = new Commands<>(bluemap, event.getCommandDispatcher(), ForgeCommandSource::new);
|
||||||
|
|
||||||
new Thread(() -> {
|
new Thread(() -> {
|
||||||
try {
|
try {
|
||||||
@ -182,7 +184,7 @@ public UUID getUUIDForWorld(ServerWorld world) throws IOException {
|
|||||||
worldUUIDs.put(key, uuid);
|
worldUUIDs.put(key, uuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
return uuid;
|
return uuid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,5 +203,9 @@ private File getFolderForWorld(ServerWorld world) throws IOException {
|
|||||||
public File getConfigFolder() {
|
public File getConfigFolder() {
|
||||||
return new File("config/bluemap");
|
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 'net.querz.nbt', 'de.bluecolored.shadow.querz.nbt'
|
||||||
relocate 'org.apache.commons.io', 'de.bluecolored.shadow.apache.commons.io'
|
relocate 'org.apache.commons.io', 'de.bluecolored.shadow.apache.commons.io'
|
||||||
|
relocate 'com.mojang.brigadier', 'de.bluecolored.shadow.mojang.brigadier'
|
||||||
|
|
||||||
minimize()
|
minimize()
|
||||||
}
|
}
|
||||||
|
@ -24,16 +24,25 @@
|
|||||||
*/
|
*/
|
||||||
package de.bluecolored.bluemap.sponge;
|
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.serverinterface.CommandSource;
|
||||||
import de.bluecolored.bluemap.common.plugin.text.Text;
|
import de.bluecolored.bluemap.common.plugin.text.Text;
|
||||||
|
import de.bluecolored.bluemap.core.world.World;
|
||||||
|
|
||||||
public class SpongeCommandSource implements CommandSource {
|
public class SpongeCommandSource implements CommandSource {
|
||||||
|
|
||||||
|
private Plugin plugin;
|
||||||
private org.spongepowered.api.command.CommandSource delegate;
|
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;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,4 +52,27 @@ public void sendMessage(Text text) {
|
|||||||
delegate.sendMessage(spongeText);
|
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;
|
package de.bluecolored.bluemap.sponge;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Optional;
|
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.CommandResult;
|
||||||
import org.spongepowered.api.command.args.GenericArguments;
|
import org.spongepowered.api.command.CommandSource;
|
||||||
import org.spongepowered.api.command.spec.CommandSpec;
|
|
||||||
import org.spongepowered.api.text.Text;
|
import org.spongepowered.api.text.Text;
|
||||||
import org.spongepowered.api.text.format.TextColors;
|
import org.spongepowered.api.text.format.TextColors;
|
||||||
import org.spongepowered.api.world.Locatable;
|
|
||||||
import org.spongepowered.api.world.Location;
|
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 {
|
public class SpongeCommands {
|
||||||
|
|
||||||
private Commands commands;
|
|
||||||
|
|
||||||
public SpongeCommands(Commands commands) {
|
|
||||||
this.commands = commands;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 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 CommandSpec createPauseRenderCommand() {
|
private CommandDispatcher<CommandSource> dispatcher;
|
||||||
return CommandSpec.builder()
|
|
||||||
.description(Text.of("Pauses all rendering"))
|
public SpongeCommands(final Plugin plugin) {
|
||||||
.permission("bluemap.pause")
|
this.dispatcher = new CommandDispatcher<>();
|
||||||
.executor((source, args) -> {
|
|
||||||
if (commands.executePauseCommand(new SpongeCommandSource(source))) {
|
// register commands
|
||||||
return CommandResult.success();
|
new Commands<>(plugin, dispatcher, bukkitSender -> new SpongeCommandSource(plugin, bukkitSender));
|
||||||
} else {
|
|
||||||
return CommandResult.empty();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandSpec createResumeRenderCommand() {
|
public Collection<SpongeCommandProxy> getRootCommands(){
|
||||||
return CommandSpec.builder()
|
Collection<SpongeCommandProxy> rootCommands = new ArrayList<>();
|
||||||
.description(Text.of("Resumes all paused rendering"))
|
|
||||||
.permission("bluemap.resume")
|
for (CommandNode<CommandSource> node : this.dispatcher.getRoot().getChildren()) {
|
||||||
.executor((source, args) -> {
|
rootCommands.add(new SpongeCommandProxy(node.getName()));
|
||||||
if (commands.executeResumeCommand(new SpongeCommandSource(source))) {
|
}
|
||||||
return CommandResult.success();
|
|
||||||
} else {
|
return rootCommands;
|
||||||
return CommandResult.empty();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public CommandSpec createRenderCommand() {
|
public class SpongeCommandProxy implements CommandCallable {
|
||||||
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);
|
|
||||||
|
|
||||||
if (spongeWorld == null && source instanceof Locatable) {
|
|
||||||
Location<org.spongepowered.api.world.World> loc = ((Locatable) source).getLocation();
|
|
||||||
spongeWorld = loc.getExtent().getProperties();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spongeWorld == null){
|
|
||||||
source.sendMessage(Text.of(TextColors.RED, "You have to define a world to render!"));
|
|
||||||
return CommandResult.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
int radius = args.<Integer>getOne("block-radius").orElse(-1);
|
private String label;
|
||||||
|
|
||||||
|
protected SpongeCommandProxy(String label) {
|
||||||
|
this.label = label;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CommandResult process(CommandSource source, String arguments) throws CommandException {
|
||||||
|
String command = label;
|
||||||
|
if (!arguments.isEmpty()) {
|
||||||
|
command += " " + arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return CommandResult.successCount(dispatcher.execute(command, source));
|
||||||
|
} catch (CommandSyntaxException ex) {
|
||||||
|
source.sendMessage(Text.of(TextColors.RED, ex.getRawMessage().getString()));
|
||||||
|
|
||||||
if (radius >= 0) {
|
String context = ex.getContext();
|
||||||
if (source instanceof Locatable) {
|
if (context != null) source.sendMessage(Text.of(TextColors.GRAY, context));
|
||||||
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();
|
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, "/" + label + " ", 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.ServerEventListener;
|
||||||
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
import de.bluecolored.bluemap.common.plugin.serverinterface.ServerInterface;
|
||||||
import de.bluecolored.bluemap.core.logger.Logger;
|
import de.bluecolored.bluemap.core.logger.Logger;
|
||||||
|
import de.bluecolored.bluemap.sponge.SpongeCommands.SpongeCommandProxy;
|
||||||
import net.querz.nbt.CompoundTag;
|
import net.querz.nbt.CompoundTag;
|
||||||
import net.querz.nbt.NBTUtil;
|
import net.querz.nbt.NBTUtil;
|
||||||
|
|
||||||
@ -65,6 +66,7 @@ public class SpongePlugin implements ServerInterface {
|
|||||||
private MetricsLite2 metrics;
|
private MetricsLite2 metrics;
|
||||||
|
|
||||||
private Plugin bluemap;
|
private Plugin bluemap;
|
||||||
|
private SpongeCommands commands;
|
||||||
|
|
||||||
private SpongeExecutorService asyncExecutor;
|
private SpongeExecutorService asyncExecutor;
|
||||||
|
|
||||||
@ -73,6 +75,7 @@ public SpongePlugin(org.slf4j.Logger logger) {
|
|||||||
Logger.global = new Slf4jLogger(logger);
|
Logger.global = new Slf4jLogger(logger);
|
||||||
|
|
||||||
this.bluemap = new Plugin("sponge", this);
|
this.bluemap = new Plugin("sponge", this);
|
||||||
|
this.commands = new SpongeCommands(bluemap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Listener
|
@Listener
|
||||||
@ -84,7 +87,10 @@ public void onServerStart(GameStartingServerEvent evt) {
|
|||||||
Sponge.getServer().saveWorldProperties(properties);
|
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(() -> {
|
asyncExecutor.execute(() -> {
|
||||||
try {
|
try {
|
||||||
|
@ -21,6 +21,9 @@ allprojects {
|
|||||||
maven {
|
maven {
|
||||||
url = 'https://files.minecraftforge.net/maven/'
|
url = 'https://files.minecraftforge.net/maven/'
|
||||||
}
|
}
|
||||||
|
maven {
|
||||||
|
url "https://libraries.minecraft.net"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava.options.compilerArgs.add '-parameters'
|
compileJava.options.compilerArgs.add '-parameters'
|
||||||
|
Loading…
Reference in New Issue
Block a user