add OnlinePlayer context for Sponge

This commit is contained in:
Aikar
2017-07-03 18:30:06 -05:00
parent dc8f95ba57
commit 5398e3f8a7
9 changed files with 244 additions and 15 deletions
@@ -0,0 +1,102 @@
package co.aikar.commands;
import com.google.common.collect.Iterables;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;
@SuppressWarnings("WeakerAccess")
public class ACFSpongeUtil {
public static Player findPlayerSmart(CommandIssuer issuer, String search) {
CommandSource requester = issuer.getIssuer();
if (search == null) {
return null;
}
String name = ACFUtil.replace(search, ":confirm", "");
if (name.length() < 3) {
issuer.sendError(MinecraftMessageKeys.USERNAME_TOO_SHORT);
return null;
}
if (!isValidName(name)) {
issuer.sendError(MinecraftMessageKeys.IS_NOT_A_VALID_NAME, "{name}", name);
return null;
}
List<Player> matches = matchPlayer(name);
List<Player> confirmList = new ArrayList<>();
findMatches(search, requester, matches, confirmList);
if (matches.size() > 1 || confirmList.size() > 1) {
String allMatches = matches.stream().map(Player::getName).collect(Collectors.joining(", "));
issuer.sendError(MinecraftMessageKeys.MULTIPLE_PLAYERS_MATCH,
"{search}", name, "{all}", allMatches);
return null;
}
if (matches.isEmpty()) {
if (confirmList.isEmpty()) {
issuer.sendError(MinecraftMessageKeys.NO_PLAYER_FOUND_SERVER,
"{search}", name);
return null;
} else {
Player player = Iterables.getOnlyElement(confirmList);
issuer.sendInfo(MinecraftMessageKeys.PLAYER_IS_VANISHED_CONFIRM, "{vanished}", player.getName());
return null;
}
}
return matches.get(0);
}
private static void findMatches(String search, CommandSource requester, List<Player> matches, List<Player> confirmList) {
// Remove vanished players from smart matching.
Iterator<Player> iter = matches.iterator();
//noinspection Duplicates
while (iter.hasNext()) {
Player player = iter.next();
if (requester instanceof Player && !((Player) requester).canSee(player)) {
if (requester.hasPermission("acf.seevanish")) {
if (!search.endsWith(":confirm")) {
confirmList.add(player);
iter.remove();
}
} else {
iter.remove();
}
}
}
}
public static List<Player> matchPlayer(String partialName) {
List<Player> matchedPlayers = new ArrayList<Player>();
for (Player iterPlayer : Sponge.getServer().getOnlinePlayers()) {
String iterPlayerName = iterPlayer.getName();
if (partialName.equalsIgnoreCase(iterPlayerName)) {
// Exact match
matchedPlayers.clear();
matchedPlayers.add(iterPlayer);
break;
}
if (iterPlayerName.toLowerCase(java.util.Locale.ENGLISH).contains(partialName.toLowerCase(java.util.Locale.ENGLISH))) {
// Partial match
matchedPlayers.add(iterPlayer);
}
}
return matchedPlayers;
}
public static boolean isValidName(String name) {
return name != null && !name.isEmpty() && ACFPatterns.VALID_NAME_PATTERN.matcher(name).matches();
}
}
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License
*
* 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 co.aikar.commands;
import co.aikar.locales.MessageKey;
public enum MinecraftMessageKeys implements MessageKeyProvider {
INVALID_WORLD,
YOU_MUST_BE_HOLDING_ITEM,
PLAYER_IS_VANISHED_CONFIRM,
USERNAME_TOO_SHORT,
IS_NOT_A_VALID_NAME,
MULTIPLE_PLAYERS_MATCH,
NO_PLAYER_FOUND_SERVER,
NO_PLAYER_FOUND
;
private final MessageKey key = MessageKey.of(this.name().toLowerCase());
public MessageKey getMessageKey() {
return key;
}
}
@@ -23,7 +23,12 @@
package co.aikar.commands;
import co.aikar.commands.annotation.Optional;
import co.aikar.commands.contexts.CommandResultSupplier;
import co.aikar.commands.contexts.OnlinePlayer;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.api.command.CommandSource;
import org.spongepowered.api.entity.living.player.Player;
@SuppressWarnings("WeakerAccess")
public class SpongeCommandContexts extends CommandContexts<SpongeCommandExecutionContext> {
@@ -32,5 +37,23 @@ public class SpongeCommandContexts extends CommandContexts<SpongeCommandExecutio
super(manager);
registerIssuerOnlyContext(CommandResultSupplier.class, c -> new CommandResultSupplier());
registerContext(OnlinePlayer.class, c -> getOnlinePlayer(c.getIssuer(), c.popFirstArg(), c.hasAnnotation(Optional.class)));
}
@Nullable
OnlinePlayer getOnlinePlayer(SpongeCommandIssuer issuer, String lookup, boolean allowMissing) throws InvalidCommandArgument {
CommandSource sender = issuer.getIssuer();
Player player = ACFSpongeUtil.findPlayerSmart(issuer, lookup);
//noinspection Duplicates
if (player == null) {
if (allowMissing) {
return null;
}
this.manager.sendMessage(sender, MessageType.ERROR, MessageKeys.COULD_NOT_FIND_PLAYER, "{search}", lookup);
throw new InvalidCommandArgument(false);
}
return new OnlinePlayer(player);
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (c) 2016-2017 Daniel Ennis (Aikar) - MIT License
*
* 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 co.aikar.commands.contexts;
import org.spongepowered.api.entity.living.player.Player;
import java.util.Objects;
public class OnlinePlayer {
public final Player player;
public OnlinePlayer(Player player) {
this.player = player;
}
public Player getPlayer() {
return this.player;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
OnlinePlayer that = (OnlinePlayer) o;
return Objects.equals(player, that.player);
}
@Override
public int hashCode() {
return Objects.hash(player);
}
@Override
public String toString() {
return "OnlinePlayer{" +
"player=" + player +
'}';
}
}