package jk_5.nailed.server.utils;
import jk_5.nailed.api.player.Player;
import jk_5.nailed.api.util.Location;
import jk_5.nailed.api.util.PlayerSelector;
public class NailedPlayerSelector implements PlayerSelector {
private static final NailedPlayerSelector INSTANCE = new NailedPlayerSelector();
private NailedPlayerSelector() {
}
/*private final val TOKEN_PATTERN = Pattern.compile("^@([parf])(?:\\[([\\w=,!-]*)\\])?$")
private final val INT_LIST_PATTERN = Pattern.compile("\\G([-!]?[\\w-]*)(?:$|,)")
private final val KEY_VALUE_LIST_PATTERN = Pattern.compile("\\G(\\w+)=([-!]?[\\w-]*)(?:$|,)")
def parseIntWithDefault(input: String, default: Int): Int = {
try{
input.toInt
}catch{
case _: NumberFormatException => default
}
}
override def matchPlayers(pattern: String, base: Location): Array[Player] = {
val tokenMatcher = TOKEN_PATTERN.matcher(pattern)
if(!tokenMatcher.matches){
val p = NailedPlatform.getPlayerByName(pattern)
if(p == null){
val p2 = NailedPlatform.getPlayer(UUID.fromString(pattern))
if(p2 == null) return new Array[Player](0) else return Array[Player](p)
}else{
return Array[Player](p)
}
}
val arguments = getArgumentMap(tokenMatcher.group(2)) //map
val typ = tokenMatcher.group(1) //s1
var minRange = 0 //i
var maxRange = 0 //j
var minXP = 0 //k
var maxXP = Int.MaxValue //l
var maxCount = if(typ == "a") 0 else 1 //i1
var gamemode: GameMode = null //j1
val scoreboardTags = getScoreboardValues(arguments) //map1
var currentWorldOnly = false
val locationBuilder = Location.builder().copy(base)
var teamName: String = null
var name: String = null
if(arguments.contains("rm")){
minRange = parseIntWithDefault(arguments.get("rm").get, minRange)
currentWorldOnly = true
}
if(arguments.contains("r")){
maxRange = parseIntWithDefault(arguments.get("r").get, minRange)
currentWorldOnly = true
}
if(arguments.contains("lm")){
minXP = parseIntWithDefault(arguments.get("lm").get, minXP)
}
if(arguments.contains("l")){
maxXP = parseIntWithDefault(arguments.get("l").get, minXP)
}
if(arguments.contains("x")){
locationBuilder.setX(parseIntWithDefault(arguments.get("x").get, locationBuilder.build().getFloorX.toInt))
currentWorldOnly = true
}
if(arguments.contains("y")){
locationBuilder.setY(parseIntWithDefault(arguments.get("r").get, locationBuilder.build().getFloorY.toInt))
currentWorldOnly = true
}
if(arguments.contains("z")){
locationBuilder.setZ(parseIntWithDefault(arguments.get("z").get, locationBuilder.build().getFloorZ.toInt))
currentWorldOnly = true
}
if(arguments.contains("m")){
gamemode = GameMode.byId(parseIntWithDefault(arguments.get("m").get, if(gamemode == null) Int.MinValue else gamemode.getId))
}
if(arguments.contains("c")){
maxCount = parseIntWithDefault(arguments.get("c").get, maxCount)
}
if(arguments.contains("team")){
teamName = arguments.get("team").get
}
if(arguments.contains("name")){
name = arguments.get("name").get
}
val location = locationBuilder.build()
val world = if(currentWorldOnly) location.getWorld else null
typ match {
case "r" =>
var l = findPlayers(location, minRange, maxRange, 0, gamemode, minXP, maxXP, scoreboardTags, name, teamName, world)
Collections.shuffle(l)
l = l.subList(0, Math.min(maxCount, l.size))
if(l.isEmpty) new Array[Player](0) else l.toArray(new Array[Player](l.size))
case "p" | "a" =>
val l = findPlayers(location, minRange, maxRange, maxCount, gamemode, minXP, maxXP, scoreboardTags, name, teamName, world)
if(l.isEmpty) new Array[Player](0) else l.toArray(new Array[Player](l.size))
case _ => new Array[Player](0)
}
}
override def matchesMultiplePlayers(pattern: String): Boolean = {
val matcher = TOKEN_PATTERN.matcher(pattern)
if(matcher.matches()){
val arguments = getArgumentMap(matcher.group(2))
val typ = matcher.group(1)
var count = if(typ == "a") 0 else 1
if(arguments.contains("c")){
count = parseIntWithDefault(arguments.get("c").get, count)
}
count != 1
}else false
}
private def findPlayers(location: Location, minRange: Int, maxRange: Int, maxCount: Int, gamemode: GameMode, minXP: Int, maxXP: Int, scoreboardTags: mutable.Map[String, String], name: String, teamName: String, world: World): util.List[Player] = {
val players = NailedPlatform.getOnlinePlayers
if(players.size() == 0) return Collections.emptyList()
val ret = new util.ArrayList[Player]()
val negativeCount = maxCount < 0 //flag
val inverseNameMatch = name != null && name.startsWith("!") //flag1
val inverseTeamNameMatch = teamName != null && name.startsWith("!") //flag2
val minRangeSq = minRange * minRange //k1
val maxRangeSq = maxRange * maxRange //l1
val count = Math.abs(maxCount) // p_1234_4_
val playerName = if(inverseNameMatch) name.substring(1) else name
val playerTeamName = if(inverseTeamNameMatch) teamName.substring(1) else teamName
val hasMap = world.getMap != null
val map = world.getMap
for(p <- players.map(_.asInstanceOf[NailedPlayer])){
var continue = false
//If world is not null, check if the player has the same world. Else check if the player has the same map
//Then check if the player's name matches the queried player name
if(((world == null && hasMap && p.world.getMap != null && p.world.getMap == map) || p.world == world) && (playerName == null || inverseNameMatch != playerName.equalsIgnoreCase(p.getName))){
if(playerTeamName != null){
val team = p.getEntity.getTeam
val teamName = if(team == null) "" else team.getRegisteredName
if(inverseTeamNameMatch == playerTeamName.equalsIgnoreCase(teamName)){
continue = true
}
}
if(!continue && location != null && (minRange > 0 || maxRange > 0)){
val dist = location.distanceSquared(p.getLocation)
if((minRange > 0 && dist < minRangeSq) || (maxRange > 0 && dist > maxRangeSq)){
continue = true
}
}
if(!continue){
//TODO: scoreboard matching! see func_96457
if(gamemode == null || gamemode == p.getGameMode){
if((minXP <= 0 || p.getEntity.experienceLevel >= minXP) && p.getEntity.experienceLevel <= maxXP){
ret.add(p)
}
}
}
}
}
Collections.sort(ret, new Comparator[Player] {
override def compare(o1: Player, o2: Player): Int = {
val dist1 = o1.asInstanceOf[NailedPlayer].getEntity.getDistanceSq(location.getX, location.getY, location.getZ)
val dist2 = o2.asInstanceOf[NailedPlayer].getEntity.getDistanceSq(location.getX, location.getY, location.getZ)
if(dist1 < dist2) -1 else{if(dist1 > dist2) 1 else 0}
}
})
if(negativeCount){
Collections.reverse(ret)
}
if(count > 0){
ret.subList(0, Math.min(count, ret.size()))
}else ret
}
private def getScoreboardValues(input: mutable.Map[String, String]): mutable.Map[String, String] = {
val ret = mutable.Map[String, String]()
for(s <- input.keys){
if(s.startsWith("score_") && s.length > 6){
val key = s.substring(6)
ret.put(key, parseIntWithDefault(input.get(s).get, 1).toString)
}
}
ret
}
private def getArgumentMap(input: String): mutable.Map[String, String] = {
if(input == null) return mutable.Map()
val matcher = INT_LIST_PATTERN.matcher(input)
val ret = mutable.Map[String, String]()
var coordIndex = 0
var i = -1
while(matcher.find()){
val key = coordIndex match {
case 0 => "x"
case 1 => "y"
case 2 => "z"
case 3 => "r"
case _ => null
}
coordIndex += 1
val value = matcher.group(1)
if(key != null && value.length > 0){
ret.put(key, value)
}
i = matcher.end()
}
if(i < input.length){
val m2 = KEY_VALUE_LIST_PATTERN.matcher(if(i == -1) input else input.substring(i))
while(m2.find()){
ret.put(matcher.group(1), matcher.group(2))
}
}
ret
}*/
@Override
public Player[] matchPlayers(String pattern, Location base) {
return new Player[0];
}
@Override
public boolean matchesMultiplePlayers(String pattern) {
return false;
}
public static NailedPlayerSelector instance() {
return INSTANCE;
}
}