From c002fbc5377bc9e7a3ed28d6434b701b9600f885 Mon Sep 17 00:00:00 2001 From: JeromSar Date: Sat, 30 May 2015 20:51:49 +0200 Subject: [PATCH] Handle player online check in AsyncPlayerPreLoginEvent Apparently, online players with the same username are kicked before PlayerLoginEvent is called. This commit moves the online player check to AsyncPlayerPreloginEvent so the default behaviour can still be modified Fixes #642 --- buildnumber.properties | 4 +- .../Commands/Command_saconfig.java | 3 +- .../Listener/TFM_PlayerListener.java | 28 ++-- .../TotalFreedomMod/TFM_AdminList.java | 2 +- .../TotalFreedomMod/TFM_PermbanList.java | 1 + .../TotalFreedomMod/TFM_PlayerList.java | 86 ++++-------- .../TotalFreedomMod/TFM_ServerInterface.java | 65 ++++++--- .../TotalFreedomMod/TFM_UuidManager.java | 132 ++++++------------ 8 files changed, 133 insertions(+), 188 deletions(-) diff --git a/buildnumber.properties b/buildnumber.properties index b3edf9b2..4c2fdec7 100644 --- a/buildnumber.properties +++ b/buildnumber.properties @@ -1,3 +1,3 @@ #Build Number for ANT. Do not edit! -#Sat May 30 20:10:27 CEST 2015 -build.number=1043 +#Sat May 30 20:46:17 CEST 2015 +build.number=1052 diff --git a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_saconfig.java b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_saconfig.java index 1f679a89..70d6121b 100644 --- a/src/me/StevenLawson/TotalFreedomMod/Commands/Command_saconfig.java +++ b/src/me/StevenLawson/TotalFreedomMod/Commands/Command_saconfig.java @@ -57,7 +57,8 @@ public class Command_saconfig extends TFM_Command { final TFM_Admin admin = TFM_AdminList.getEntry(sender_p); - if (admin == null) { + if (admin == null) + { playerMsg("Could not find your admin entry! Please notify a developer.", ChatColor.RED); return true; } diff --git a/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_PlayerListener.java b/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_PlayerListener.java index 12250cf4..7de5fd3c 100644 --- a/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_PlayerListener.java +++ b/src/me/StevenLawson/TotalFreedomMod/Listener/TFM_PlayerListener.java @@ -45,6 +45,7 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.block.LeavesDecayEvent; import org.bukkit.event.player.AsyncPlayerChatEvent; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.player.PlayerDropItemEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -388,7 +389,7 @@ public class TFM_PlayerListener implements Listener final Player player = event.getPlayer(); final TFM_PlayerData playerdata = TFM_PlayerData.getPlayerData(player); // Check absolute value to account for negatives - if(Math.abs(event.getTo().getX()) >= MAX_XY_COORD || Math.abs(event.getTo().getZ()) >= MAX_XY_COORD) + if (Math.abs(event.getTo().getX()) >= MAX_XY_COORD || Math.abs(event.getTo().getZ()) >= MAX_XY_COORD) { event.setCancelled(true); // illegal position, cancel it } @@ -791,7 +792,7 @@ public class TFM_PlayerListener implements Listener final TFM_Player playerEntry; TFM_Log.info("[JOIN] " + TFM_Util.formatPlayer(player) + " joined the game with IP address: " + ip, true); // Check absolute value to account for negatives - if(Math.abs(player.getLocation().getX()) >= MAX_XY_COORD || Math.abs(player.getLocation().getZ()) >= MAX_XY_COORD) + if (Math.abs(player.getLocation().getX()) >= MAX_XY_COORD || Math.abs(player.getLocation().getZ()) >= MAX_XY_COORD) { player.teleport(player.getWorld().getSpawnLocation()); // Illegal position, teleport to spawn } @@ -911,26 +912,15 @@ public class TFM_PlayerListener implements Listener }.runTaskLater(TotalFreedomMod.plugin, 20L * 1L); } + @EventHandler(priority = EventPriority.HIGHEST) + public void onPlayerPreLogin(AsyncPlayerPreLoginEvent event) + { + TFM_ServerInterface.handlePlayerPreLogin(event); + } + @EventHandler(priority = EventPriority.HIGHEST) public void onPlayerLogin(PlayerLoginEvent event) { - if (TFM_ConfigEntry.FORCE_IP_ENABLED.getBoolean()) - { - final String hostname = event.getHostname().replace("FML", ""); // Forge fix - https://github.com/TotalFreedom/TotalFreedomMod/issues/493 - final String connectAddress = TFM_ConfigEntry.SERVER_ADDRESS.getString(); - final int connectPort = TotalFreedomMod.server.getPort(); - - if (!hostname.equalsIgnoreCase(connectAddress + ":" + connectPort) && !hostname.equalsIgnoreCase(connectAddress + ".:" + connectPort)) - { - final int forceIpPort = TFM_ConfigEntry.FORCE_IP_PORT.getInteger(); - event.disallow(PlayerLoginEvent.Result.KICK_OTHER, - TFM_ConfigEntry.FORCE_IP_KICKMSG.getString() - .replace("%address%", TFM_ConfigEntry.SERVER_ADDRESS.getString() + (forceIpPort == DEFAULT_PORT ? "" : ":" + forceIpPort))); - return; - } - - } - TFM_ServerInterface.handlePlayerLogin(event); } } diff --git a/src/me/StevenLawson/TotalFreedomMod/TFM_AdminList.java b/src/me/StevenLawson/TotalFreedomMod/TFM_AdminList.java index 68ef5d97..7941087e 100644 --- a/src/me/StevenLawson/TotalFreedomMod/TFM_AdminList.java +++ b/src/me/StevenLawson/TotalFreedomMod/TFM_AdminList.java @@ -406,7 +406,7 @@ public class TFM_AdminList public static boolean isSuperAdminSafe(UUID uuid, String ip) { - if (TotalFreedomMod.server.getOnlineMode()) + if (TotalFreedomMod.server.getOnlineMode() && uuid != null) { return TFM_AdminList.getSuperUUIDs().contains(uuid); } diff --git a/src/me/StevenLawson/TotalFreedomMod/TFM_PermbanList.java b/src/me/StevenLawson/TotalFreedomMod/TFM_PermbanList.java index d888cbb7..27d9e0ec 100644 --- a/src/me/StevenLawson/TotalFreedomMod/TFM_PermbanList.java +++ b/src/me/StevenLawson/TotalFreedomMod/TFM_PermbanList.java @@ -7,6 +7,7 @@ import me.StevenLawson.TotalFreedomMod.Config.TFM_Config; public class TFM_PermbanList { + private static final List PERMBANNED_PLAYERS; private static final List PERMBANNED_IPS; diff --git a/src/me/StevenLawson/TotalFreedomMod/TFM_PlayerList.java b/src/me/StevenLawson/TotalFreedomMod/TFM_PlayerList.java index 7f985f4a..418ee5f8 100644 --- a/src/me/StevenLawson/TotalFreedomMod/TFM_PlayerList.java +++ b/src/me/StevenLawson/TotalFreedomMod/TFM_PlayerList.java @@ -11,65 +11,53 @@ import me.StevenLawson.TotalFreedomMod.Config.TFM_Config; import org.bukkit.Bukkit; import org.bukkit.entity.Player; -public class TFM_PlayerList -{ +public class TFM_PlayerList { + private static final Map PLAYER_LIST = new HashMap(); - private TFM_PlayerList() - { + private TFM_PlayerList() { throw new AssertionError(); } - public static Set getAllPlayers() - { + public static Set getAllPlayers() { return Collections.unmodifiableSet(Sets.newHashSet(PLAYER_LIST.values())); } - public static void load() - { + public static void load() { PLAYER_LIST.clear(); // Load online players - for (Player player : Bukkit.getOnlinePlayers()) - { + for (Player player : Bukkit.getOnlinePlayers()) { getEntry(player); } TFM_Log.info("Loaded playerdata for " + PLAYER_LIST.size() + " players"); } - public static void saveAll() - { - for (TFM_Player entry : PLAYER_LIST.values()) - { + public static void saveAll() { + for (TFM_Player entry : PLAYER_LIST.values()) { save(entry); } } // May return null - public static TFM_Player getEntry(UUID uuid) - { - if (PLAYER_LIST.containsKey(uuid)) - { + public static TFM_Player getEntry(UUID uuid) { + if (PLAYER_LIST.containsKey(uuid)) { return PLAYER_LIST.get(uuid); } final File configFile = getConfigFile(uuid); - if (!configFile.exists()) - { + if (!configFile.exists()) { return null; } final TFM_Player entry = new TFM_Player(uuid, getConfig(uuid)); - if (entry.isComplete()) - { + if (entry.isComplete()) { PLAYER_LIST.put(uuid, entry); return entry; - } - else - { + } else { TFM_Log.warning("Could not load entry: Entry is not complete!"); configFile.delete(); } @@ -77,13 +65,11 @@ public class TFM_PlayerList return null; } - public static TFM_Player getEntry(Player player) - { + public static TFM_Player getEntry(Player player) { final UUID uuid = TFM_UuidManager.getUniqueId(player); TFM_Player entry = getEntry(uuid); - if (entry != null) - { + if (entry != null) { return entry; } @@ -101,12 +87,10 @@ public class TFM_PlayerList return entry; } - public static void removeEntry(Player player) - { + public static void removeEntry(Player player) { final UUID uuid = TFM_UuidManager.getUniqueId(player); - if (!PLAYER_LIST.containsKey(uuid)) - { + if (!PLAYER_LIST.containsKey(uuid)) { return; } @@ -115,20 +99,16 @@ public class TFM_PlayerList PLAYER_LIST.remove(uuid); } - public static boolean existsEntry(Player player) - { + public static boolean existsEntry(Player player) { return existsEntry(TFM_UuidManager.getUniqueId(player)); } - public static boolean existsEntry(UUID uuid) - { + public static boolean existsEntry(UUID uuid) { return getConfigFile(uuid).exists(); } - public static void setUniqueId(TFM_Player entry, UUID newUuid) - { - if (entry.getUniqueId().equals(newUuid)) - { + public static void setUniqueId(TFM_Player entry, UUID newUuid) { + if (entry.getUniqueId().equals(newUuid)) { TFM_Log.warning("Not setting new UUID: UUIDs match!"); return; } @@ -147,16 +127,13 @@ public class TFM_PlayerList // Remove old entry PLAYER_LIST.remove(entry.getUniqueId()); final File oldFile = getConfigFile(entry.getUniqueId()); - if (oldFile.exists() && !oldFile.delete()) - { + if (oldFile.exists() && !oldFile.delete()) { TFM_Log.warning("Could not delete config: " + getConfigFile(entry.getUniqueId()).getName()); } } - public static void purgeAll() - { - for (File file : getConfigFolder().listFiles()) - { + public static void purgeAll() { + for (File file : getConfigFolder().listFiles()) { file.delete(); } @@ -164,27 +141,22 @@ public class TFM_PlayerList load(); } - public static File getConfigFolder() - { + public static File getConfigFolder() { return new File(TotalFreedomMod.plugin.getDataFolder(), "players"); } - public static File getConfigFile(UUID uuid) - { + public static File getConfigFile(UUID uuid) { return new File(getConfigFolder(), uuid + ".yml"); } - public static TFM_Config getConfig(UUID uuid) - { + public static TFM_Config getConfig(UUID uuid) { final TFM_Config config = new TFM_Config(TotalFreedomMod.plugin, getConfigFile(uuid), false); config.load(); return config; } - public static void save(TFM_Player entry) - { - if (!entry.isComplete()) - { + public static void save(TFM_Player entry) { + if (!entry.isComplete()) { throw new IllegalArgumentException("Entry is not complete!"); } diff --git a/src/me/StevenLawson/TotalFreedomMod/TFM_ServerInterface.java b/src/me/StevenLawson/TotalFreedomMod/TFM_ServerInterface.java index 4b46c4b3..0f7ea8f0 100644 --- a/src/me/StevenLawson/TotalFreedomMod/TFM_ServerInterface.java +++ b/src/me/StevenLawson/TotalFreedomMod/TFM_ServerInterface.java @@ -5,12 +5,14 @@ import java.util.List; import java.util.UUID; import java.util.regex.Pattern; import me.StevenLawson.TotalFreedomMod.Config.TFM_ConfigEntry; +import static me.StevenLawson.TotalFreedomMod.Listener.TFM_PlayerListener.DEFAULT_PORT; import net.minecraft.server.v1_8_R2.EntityPlayer; import net.minecraft.server.v1_8_R2.MinecraftServer; import net.minecraft.server.v1_8_R2.PropertyManager; import org.bukkit.ChatColor; import org.bukkit.Server; import org.bukkit.entity.Player; +import org.bukkit.event.player.AsyncPlayerPreLoginEvent; import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent.Result; @@ -62,6 +64,29 @@ public class TFM_ServerInterface return MinecraftServer.getServer().getVersion(); } + public static void handlePlayerPreLogin(AsyncPlayerPreLoginEvent event) + { + final String ip = event.getAddress().getHostAddress().trim(); + final boolean isAdmin = TFM_AdminList.isSuperAdminSafe(null, ip); + + // Check if the player is already online + for (Player onlinePlayer : TotalFreedomMod.server.getOnlinePlayers()) + { + if (!onlinePlayer.getName().equalsIgnoreCase(event.getName())) + { + continue; + } + + if (!isAdmin) { + event.disallow(AsyncPlayerPreLoginEvent.Result.KICK_OTHER, "Your username is already logged into this server."); + } else { + event.allow(); + TFM_Sync.playerKick(onlinePlayer, "An admin just logged in with the username you are using."); + } + return; + } + } + public static void handlePlayerLogin(PlayerLoginEvent event) { final Server server = TotalFreedomMod.server; @@ -70,19 +95,38 @@ public class TFM_ServerInterface final String ip = event.getAddress().getHostAddress().trim(); final UUID uuid = TFM_UuidManager.newPlayer(player, ip); - // Perform username checks + // Check username length if (username.length() < 3 || username.length() > TotalFreedomMod.MAX_USERNAME_LENGTH) { event.disallow(Result.KICK_OTHER, "Your username is an invalid length (must be between 3 and 20 characters long)."); return; } + // Check username characters if (!USERNAME_REGEX.matcher(username).find()) { event.disallow(Result.KICK_OTHER, "Your username contains invalid characters."); return; } + // Check force-IP match + if (TFM_ConfigEntry.FORCE_IP_ENABLED.getBoolean()) + { + final String hostname = event.getHostname().replace("FML", ""); // Forge fix - https://github.com/TotalFreedom/TotalFreedomMod/issues/493 + final String connectAddress = TFM_ConfigEntry.SERVER_ADDRESS.getString(); + final int connectPort = TotalFreedomMod.server.getPort(); + + if (!hostname.equalsIgnoreCase(connectAddress + ":" + connectPort) && !hostname.equalsIgnoreCase(connectAddress + ".:" + connectPort)) + { + final int forceIpPort = TFM_ConfigEntry.FORCE_IP_PORT.getInteger(); + event.disallow(PlayerLoginEvent.Result.KICK_OTHER, + TFM_ConfigEntry.FORCE_IP_KICKMSG.getString() + .replace("%address%", TFM_ConfigEntry.SERVER_ADDRESS.getString() + (forceIpPort == DEFAULT_PORT ? "" : ":" + forceIpPort))); + return; + } + + } + // Check if player is admin // Not safe to use TFM_Util.isSuperAdmin(player) because player.getAddress() will return a null until after player login. final boolean isAdmin = TFM_AdminList.isSuperAdminSafe(uuid, ip); @@ -93,15 +137,6 @@ public class TFM_ServerInterface // Force-allow log in event.allow(); - // Kick players with the same name - for (Player onlinePlayer : server.getOnlinePlayers()) - { - if (onlinePlayer.getName().equalsIgnoreCase(username)) - { - onlinePlayer.kickPlayer("An admin just logged in with the username you are using."); - } - } - int count = server.getOnlinePlayers().size(); if (count >= server.getMaxPlayers()) { @@ -151,16 +186,6 @@ public class TFM_ServerInterface return; } - // Username already logged in - for (Player onlinePlayer : server.getOnlinePlayers()) - { - if (onlinePlayer.getName().equalsIgnoreCase(username)) - { - event.disallow(Result.KICK_OTHER, "Your username is already logged into this server."); - return; - } - } - // Whitelist if (isWhitelisted()) { diff --git a/src/me/StevenLawson/TotalFreedomMod/TFM_UuidManager.java b/src/me/StevenLawson/TotalFreedomMod/TFM_UuidManager.java index 086f02be..71fde308 100644 --- a/src/me/StevenLawson/TotalFreedomMod/TFM_UuidManager.java +++ b/src/me/StevenLawson/TotalFreedomMod/TFM_UuidManager.java @@ -25,20 +25,18 @@ import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.parser.JSONParser; -public class TFM_UuidManager -{ +public class TFM_UuidManager { + public static final String TABLE_NAME = "uuids"; private static final TFM_SqliteDatabase SQL; private static final Statement FIND; private static final Statement UPDATE; - private TFM_UuidManager() - { + private TFM_UuidManager() { throw new AssertionError(); } - static - { + static { SQL = new TFM_SqliteDatabase( "uuids.db", TABLE_NAME, @@ -48,40 +46,34 @@ public class TFM_UuidManager UPDATE = SQL.addPreparedStatement("REPLACE INTO " + TABLE_NAME + " (username, uuid) VALUES (?, ?);"); } - public static void load() - { + public static void load() { // Init DB SQL.connect(); } - public static void close() - { + public static void close() { SQL.close(); } - public static int purge() - { + public static int purge() { return SQL.purge(); } - public static UUID newPlayer(Player player, String ip) - { + public static UUID newPlayer(Player player, String ip) { TFM_Log.info("Obtaining UUID for new player: " + player.getName()); final String username = player.getName().toLowerCase(); // Look in DB final UUID dbUuid = find(username); - if (dbUuid != null) - { + if (dbUuid != null) { return dbUuid; } // Find UUID and update in DB if not found // Try API UUID uuid = TFM_UuidResolver.getUUIDOf(username); - if (uuid == null) - { + if (uuid == null) { // Spoof uuid = generateSpoofUuid(username); } @@ -90,11 +82,9 @@ public class TFM_UuidManager return uuid; } - public static UUID getUniqueId(OfflinePlayer offlinePlayer) - { + public static UUID getUniqueId(OfflinePlayer offlinePlayer) { // Online check first - if (offlinePlayer.isOnline() && TFM_PlayerData.hasPlayerData(offlinePlayer.getPlayer())) - { + if (offlinePlayer.isOnline() && TFM_PlayerData.hasPlayerData(offlinePlayer.getPlayer())) { return TFM_PlayerData.getPlayerData(offlinePlayer.getPlayer()).getUniqueId(); } @@ -102,19 +92,16 @@ public class TFM_UuidManager return getUniqueId(offlinePlayer.getName()); } - public static UUID getUniqueId(String username) - { + public static UUID getUniqueId(String username) { // Look in DB final UUID dbUuid = find(username); - if (dbUuid != null) - { + if (dbUuid != null) { return dbUuid; } // Try API final UUID apiUuid = TFM_UuidResolver.getUUIDOf(username); - if (apiUuid != null) - { + if (apiUuid != null) { return apiUuid; } @@ -122,10 +109,8 @@ public class TFM_UuidManager return generateSpoofUuid(username); } - public static void rawSetUUID(String name, UUID uuid) - { - if (name == null || uuid == null || name.isEmpty()) - { + public static void rawSetUUID(String name, UUID uuid) { + if (name == null || uuid == null || name.isEmpty()) { TFM_Log.warning("Not setting raw UUID: name and uuid may not be null!"); return; } @@ -133,86 +118,67 @@ public class TFM_UuidManager update(name.toLowerCase().trim(), uuid); } - private static UUID find(String searchName) - { - if (!SQL.connect()) - { + private static UUID find(String searchName) { + if (!SQL.connect()) { return null; } final ResultSet result; - try - { + try { final PreparedStatement statement = FIND.getStatement(); statement.clearParameters(); statement.setString(1, searchName.toLowerCase()); result = statement.executeQuery(); - } - catch (Exception ex) - { + } catch (Exception ex) { TFM_Log.severe("Could not execute find statement!"); TFM_Log.severe(ex); return null; } - if (!TFM_SqlUtil.hasData(result)) - { + if (!TFM_SqlUtil.hasData(result)) { TFM_SqlUtil.close(result); return null; } - try - { + try { final String uuidString = result.getString("uuid"); return UUID.fromString(uuidString); - } - catch (Exception ex) - { + } catch (Exception ex) { TFM_Log.severe(ex); return null; - } - finally - { + } finally { TFM_SqlUtil.close(result); } } - private static boolean update(String username, UUID uuid) - { - if (!SQL.connect()) - { + private static boolean update(String username, UUID uuid) { + if (!SQL.connect()) { return false; } - try - { + try { final PreparedStatement statement = UPDATE.getStatement(); statement.clearParameters(); statement.setString(1, username.toLowerCase()); statement.setString(2, uuid.toString()); statement.executeUpdate(); return true; - } - catch (Exception ex) - { + } catch (Exception ex) { TFM_Log.severe("Could not execute update statement!"); TFM_Log.severe(ex); return false; } } - private static UUID generateSpoofUuid(String name) - { + private static UUID generateSpoofUuid(String name) { name = name.toLowerCase(); TFM_Log.info("Generating spoof UUID for " + name); - try - { + try { final MessageDigest digest = MessageDigest.getInstance("SHA1"); final byte[] result = digest.digest(name.getBytes()); final StringBuilder builder = new StringBuilder(); - for (int i = 0; i < result.length; i++) - { + for (int i = 0; i < result.length; i++) { builder.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1)); } @@ -222,36 +188,30 @@ public class TFM_UuidManager + "-" + builder.substring(12, 16) + "-" + builder.substring(16, 20) + "-" + builder.substring(20, 32)); - } - catch (NoSuchAlgorithmException ex) - { + } catch (NoSuchAlgorithmException ex) { TFM_Log.warning("Could not generate spoof UUID: SHA1 algorithm not found!"); } return UUID.randomUUID(); } - public static class TFM_UuidResolver implements Callable> - { + public static class TFM_UuidResolver implements Callable> { + private static final double PROFILES_PER_REQUEST = 100; private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; private final JSONParser jsonParser = new JSONParser(); private final List names; - public TFM_UuidResolver(List names) - { + public TFM_UuidResolver(List names) { this.names = ImmutableList.copyOf(names); } @Override - public Map call() - { + public Map call() { final Map uuidMap = new HashMap(); int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST); - for (int i = 0; i < requests; i++) - { - try - { + for (int i = 0; i < requests; i++) { + try { final URL url = new URL(PROFILE_URL); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); @@ -270,8 +230,7 @@ public class TFM_UuidManager final JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream())); - for (Object profile : array) - { + for (Object profile : array) { final JSONObject jsonProfile = (JSONObject) profile; final String id = (String) jsonProfile.get("id"); final String name = (String) jsonProfile.get("name"); @@ -284,13 +243,10 @@ public class TFM_UuidManager uuidMap.put(name, uuid); } - if (i != requests - 1) - { + if (i != requests - 1) { Thread.sleep(100L); } - } - catch (Exception ex) - { + } catch (Exception ex) { TFM_Log.severe("Could not resolve UUID(s) of " + StringUtils.join(names.subList(i * 100, Math.min((i + 1) * 100, names.size())), ", ")); //TFM_Log.severe(ex); @@ -299,9 +255,9 @@ public class TFM_UuidManager return uuidMap; } - public static UUID getUUIDOf(String name) - { + public static UUID getUUIDOf(String name) { return new TFM_UuidResolver(Arrays.asList(name)).call().get(name); } } + }