ProjectAres/Commons/bukkit/src/main/java/tc/oc/commons/bukkit/commands/MiscCommands.java

298 lines
13 KiB
Java

package tc.oc.commons.bukkit.commands;
import com.sk89q.minecraft.util.commands.Command;
import com.sk89q.minecraft.util.commands.CommandContext;
import com.sk89q.minecraft.util.commands.CommandException;
import com.sk89q.minecraft.util.commands.CommandPermissions;
import com.sk89q.minecraft.util.commands.CommandPermissionsException;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.TranslatableComponent;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import tc.oc.api.bukkit.users.BukkitUserStore;
import tc.oc.api.docs.virtual.UserDoc;
import tc.oc.api.users.UserService;
import tc.oc.commons.bukkit.chat.Audiences;
import tc.oc.commons.bukkit.chat.HeaderComponent;
import tc.oc.commons.bukkit.chat.PlayerComponent;
import tc.oc.commons.bukkit.nick.IdentityProvider;
import tc.oc.commons.core.chat.Audience;
import tc.oc.commons.core.chat.Component;
import tc.oc.commons.core.commands.Commands;
import tc.oc.commons.core.concurrent.Flexecutor;
import tc.oc.commons.core.stream.Collectors;
import tc.oc.commons.core.util.Streams;
import tc.oc.minecraft.protocol.MinecraftVersion;
import tc.oc.minecraft.scheduler.Sync;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
* Commands for miscellaneous purposes.
*/
public class MiscCommands implements Commands {
private final Flexecutor flexecutor;
private final UserService userService;
private final BukkitUserStore userStore;
private final UserFinder userFinder;
private final IdentityProvider identityProvider;
private final Audiences audiences;
@Inject MiscCommands(@Sync Flexecutor flexecutor, UserService userService, BukkitUserStore userStore, UserFinder userFinder, IdentityProvider identityProvider, Audiences audiences) {
this.flexecutor = flexecutor;
this.userService = userService;
this.userStore = userStore;
this.userFinder = userFinder;
this.identityProvider = identityProvider;
this.audiences = audiences;
}
@Command(
aliases = { "playerversion", "pv" },
desc = "Shows statics on what version players online are using",
flags = "ad",
min = 0,
max = 1
)
@CommandPermissions("ocn.version")
public void listPlayerVersions(final CommandContext args, final CommandSender sender) throws CommandException {
Audience audience = audiences.get(sender);
if (args.hasFlag('a')) {
Map<String, Integer> playerCountVersionMap = new HashMap<>();
userStore.stream().forEach(player -> {
String version = MinecraftVersion.describeProtocol(player.getProtocolVersion(), !args.hasFlag('d'));
playerCountVersionMap.put(version, playerCountVersionMap.getOrDefault(version, 0) + 1);
});
audience.sendMessage(new HeaderComponent(new Component(ChatColor.AQUA).translate("list.player.versions.title")));
for (Map.Entry<String, Integer> entry : playerCountVersionMap.entrySet()) {
audience.sendMessage(new TranslatableComponent("list.player.versions.message." + (entry.getValue() == 1 ? "singular" : "plural"),
ChatColor.AQUA + entry.getValue().toString(),
ChatColor.AQUA + entry.getKey(),
String.format("%.1f", 100 * entry.getValue() / (double) userStore.count()) + "%"));
}
} else {
Player player = CommandUtils.getPlayerOrSelf(args, sender, 0);
audience.sendMessage(new TranslatableComponent("list.player.version.singular.message", new PlayerComponent(identityProvider.createIdentity(player)), ChatColor.AQUA + MinecraftVersion.describeProtocol(player.getProtocolVersion(), false)));
}
}
@Command(
aliases = { "playerlocale", "locale" },
desc = "Shows statics on what locale players online are in",
flags = "a",
min = 0,
max = 1
)
@CommandPermissions("ocn.locale")
public void listPlayerLocales(final CommandContext args, final CommandSender sender) throws CommandException {
Audience audience = audiences.get(sender);
if (args.hasFlag('a')) {
Map<String, Long> playerLocaleMap = userStore.stream().collect(java.util.stream.Collectors.groupingBy(Player::getLocale, java.util.stream.Collectors.counting()));
audience.sendMessage(new HeaderComponent(new Component(ChatColor.AQUA).translate("list.player.locales.title")));
for (Map.Entry<String, Long> entry : playerLocaleMap.entrySet()) {
audience.sendMessage(new TranslatableComponent("list.player.locales.message." + (entry.getValue() == 1 ? "singular" : "plural"),
ChatColor.AQUA + entry.getValue().toString(),
ChatColor.AQUA + entry.getKey(),
String.format("%.1f", 100 * entry.getValue() / (double) userStore.count()) + "%"));
}
} else {
Player player = CommandUtils.getPlayerOrSelf(args, sender, 0);
audience.sendMessage(new TranslatableComponent("list.player.locale.singular.message", new PlayerComponent(identityProvider.createIdentity(player)), ChatColor.AQUA + player.getLocale()));
}
}
@Command(
aliases = { "coinflip" },
desc = "Flip a Coin",
flags = "b",
min = 0,
max = 0
)
@CommandPermissions("coinflip")
public void coinFlip(final CommandContext args, final CommandSender sender) throws CommandException {
if (args.hasFlag('b')) {
Bukkit.broadcastMessage(ChatColor.AQUA + (Math.random() < 0.5 ? "Heads" : "Tails"));
} else {
sender.sendMessage(ChatColor.AQUA + (Math.random() < 0.5 ? "Heads" : "Tails"));
}
}
@Command(
aliases = { "togglegravity" },
usage = "<player>",
desc = "Toggle a player's gravity.",
min = 0,
max = 1
)
@CommandPermissions("togglegravity")
public void noGravity(final CommandContext args, final CommandSender sender) throws CommandException {
Player player = CommandUtils.getPlayerOrSelf(args, sender, 0);
player.setGravity(!player.hasGravity());
}
@Command(
aliases = { "join-friend-tokens" },
usage = "<player> <concurrent> <limit>",
desc = "Change the join friend tokens limit for a premium player",
min = 3
)
public void joinFriend(final CommandContext args, final CommandSender sender) throws CommandException {
if(!(sender instanceof ConsoleCommandSender)) throw new CommandPermissionsException();
int concurrent = args.getInteger(1, 1);
int limit = args.getInteger(2, 3);
flexecutor.callback(
userFinder.findLocalPlayer(sender, args, 0),
response -> {
userService.update(response.user, new UserDoc.FriendTokens() {
@Override
public int friend_tokens_limit() {
return limit;
}
@Override
public int friend_tokens_concurrent() {
return concurrent;
}
});
}
);
}
@Command(
aliases = { "change-death-screen" },
usage = "<player> <+1/-1>",
desc = "Allow a player to change their death screen",
min = 2
)
public void deathScreen(final CommandContext args, final CommandSender sender) throws CommandException {
if(!(sender instanceof ConsoleCommandSender)) throw new CommandPermissionsException();
boolean enable = args.getInteger(1, +1) > 0;
flexecutor.callback(
userFinder.findLocalPlayer(sender, args, 0),
response -> {
if((response.user.death_screen() == null) != enable) {
userService.update(response.user, (UserDoc.DeathScreen) () -> enable ? "default" : null);
}
}
);
}
@Command(
aliases = { "sudo" },
usage = "<player> [command... (rand|mode|near|color|*)=value]",
desc = "Run a command as console or another player",
flags = "cd",
anyFlags = true,
min = 1,
max = -1
)
@CommandPermissions("sudo")
public void sudo(final CommandContext args, final CommandSender sender) throws CommandException {
Server server = sender.getServer();
int index = 1;
CommandSender other = userStore.find(args.getString(0, ""));
if(other == null) {
other = args.hasFlag('c') ? server.getConsoleSender() : sender;
index = 0;
}
if(!sender.equals(other) && !sender.hasPermission("sudo.others")) {
throw new CommandPermissionsException();
}
String command = args.getJoinedStrings(index);
List<String> commands = getPermutations(sender, command);
String explanation;
if(commands.size() == 1) {
explanation = "/" + commands.get(0);
} else {
explanation = commands.size() + ChatColor.WHITE.toString() + " commands";
}
sender.sendMessage("Executing " + ChatColor.AQUA + explanation + ChatColor.WHITE + " as " + identityProvider.currentIdentity(other).getName(sender));
for(String cmd : commands) {
if(commands.size() > 1 && args.hasFlag('d')) {
sender.sendMessage(" > " + cmd);
}
server.dispatchCommand(other, cmd);
}
}
public List<String> getPermutations(CommandSender sender, String command) throws CommandException {
List<String> permutations = new ArrayList<>();
getPermutations(sender, command, permutations);
return permutations;
}
public void getPermutations(CommandSender sender, String command, List<String> commands) throws CommandException {
Matcher matcher = Pattern.compile("\\*|[A-Za-z]{1,}=[A-Za-z0-9_-]{1,}").matcher(command);
if(matcher.find()) {
String keyValue = matcher.group();
for(String name : getPlayers(sender, keyValue).map(player -> player.getName(sender)).collect(Collectors.toImmutableList())) {
getPermutations(sender, matcher.replaceFirst(name), commands);
}
} else {
commands.add(command);
}
}
public Stream<Player> getPlayers(CommandSender sender, String keyValue) throws CommandException {
Stream<Player> players = userStore.stream();
int seperator = keyValue.indexOf("=");
String key = seperator != -1 ? keyValue.substring(0, seperator) : keyValue;
String value = seperator != -1 ? keyValue.substring(seperator + 1, keyValue.length()) : "";
int parsed;
try {
parsed = Integer.parseInt(value);
} catch(NumberFormatException nfe) {
parsed = -1;
}
int valueInt = parsed;
switch(key) {
case "rand":
return players.collect(Collectors.toRandomSubList(valueInt)).stream();
case "mode":
return players.filter(p -> p.getGameMode().getValue() == valueInt);
case "near":
Location location = CommandUtils.senderToPlayer(sender).getLocation();
return players.filter(p -> p.getLocation().distance(location) <= valueInt);
case "color":
ChatColor color = CommandUtils.getEnum(value, sender, ChatColor.class, ChatColor.WHITE);
return players.filter(p -> getFuzzyColor(p).equals(color));
case "perm":
return players.filter(p -> p.hasPermission(value));
case "*":
return Streams.shuffle(players);
default:
throw new CommandException("Unrecognized player filter '" + key + "'");
}
}
public ChatColor getFuzzyColor(CommandSender sender) {
if(sender instanceof Player) {
Player player = (Player) sender;
Matcher matcher = ChatColor.STRIP_COLOR_PATTERN.matcher(player.getDisplayName(sender));
String color = null;
while(matcher.find()) {
color = matcher.group();
}
if(color != null) {
return ChatColor.getByChar(color.charAt(1));
}
}
return ChatColor.WHITE;
}
}