mirror of
https://github.com/Brettflan/WorldBorder.git
synced 2024-11-22 18:16:24 +01:00
Changed bypass list to track UUIDs instead of names, in advance of changeable names in Minecraft 1.8.0+. There might be a slight delay in response now when running the /wb bypasslist command, and when running the /wb bypass command on a player who is not online. This is because the Mojang UUID lookup server must be queried in those cases. This may be handled better in a future update if/when Bukkit provides methods for caching and looking up that information.
The UUID/player name lookup code I've used is by evilmidget38, from: http://forums.bukkit.org/threads/player-name-uuid-fetcher.250926/ NOTE: if you have a bypass list saved, it will be wiped when you first run this update. The wipe will only happen once, as it is a safety precaution.
This commit is contained in:
parent
1698548fb5
commit
2984d9513f
2
pom.xml
2
pom.xml
@ -30,7 +30,7 @@
|
||||
<dependency>
|
||||
<groupId>org.bukkit</groupId>
|
||||
<artifactId>bukkit</artifactId>
|
||||
<version>1.7.2-R0.4-SNAPSHOT</version>
|
||||
<version>1.7.9-R0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.dynmap</groupId>
|
||||
|
@ -53,7 +53,7 @@ public class BorderCheckTask implements Runnable
|
||||
return null;
|
||||
|
||||
// if player is in bypass list (from bypass command), allow them beyond border; also ignore players currently being handled already
|
||||
if (Config.isPlayerBypassing(player.getName()) || handlingPlayers.contains(player.getName().toLowerCase()))
|
||||
if (Config.isPlayerBypassing(player.getUniqueId()) || handlingPlayers.contains(player.getName().toLowerCase()))
|
||||
return null;
|
||||
|
||||
// tag this player as being handled so we can't get stuck in a loop due to Bukkit currently sometimes repeatedly providing incorrect location through teleport event
|
||||
|
@ -6,11 +6,13 @@ import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.FileConfiguration;
|
||||
@ -36,7 +38,7 @@ public class Config
|
||||
// actual configuration values which can be changed
|
||||
private static boolean shapeRound = true;
|
||||
private static Map<String, BorderData> borders = Collections.synchronizedMap(new LinkedHashMap<String, BorderData>());
|
||||
private static Set<String> bypassPlayers = Collections.synchronizedSet(new LinkedHashSet<String>());
|
||||
private static Set<UUID> bypassPlayers = Collections.synchronizedSet(new LinkedHashSet<UUID>());
|
||||
private static String message; // raw message without color code formatting
|
||||
private static String messageFmt; // message with color code formatting ("&" changed to funky sort-of-double-dollar-sign for legitimate color/formatting codes)
|
||||
private static String messageClean; // message cleaned of formatting codes
|
||||
@ -373,32 +375,42 @@ public class Config
|
||||
return dynmapMessage;
|
||||
}
|
||||
|
||||
public static void setPlayerBypass(String player, boolean bypass)
|
||||
public static void setPlayerBypass(UUID player, boolean bypass)
|
||||
{
|
||||
if (bypass)
|
||||
bypassPlayers.add(player.toLowerCase());
|
||||
bypassPlayers.add(player);
|
||||
else
|
||||
bypassPlayers.remove(player.toLowerCase());
|
||||
bypassPlayers.remove(player);
|
||||
save(true);
|
||||
}
|
||||
|
||||
public static boolean isPlayerBypassing(String player)
|
||||
public static boolean isPlayerBypassing(UUID player)
|
||||
{
|
||||
return bypassPlayers.contains(player.toLowerCase());
|
||||
return bypassPlayers.contains(player);
|
||||
}
|
||||
|
||||
public static void togglePlayerBypass(String player)
|
||||
public static ArrayList<UUID> getPlayerBypassList()
|
||||
{
|
||||
setPlayerBypass(player, !isPlayerBypassing(player));
|
||||
return new ArrayList(bypassPlayers);
|
||||
}
|
||||
|
||||
public static String getPlayerBypassList()
|
||||
// for converting bypass UUID list to/from String list, for storage in config
|
||||
private static void importBypassStringList(List<String> strings)
|
||||
{
|
||||
if (bypassPlayers.isEmpty())
|
||||
return "<none>";
|
||||
String newString = bypassPlayers.toString();
|
||||
return newString.substring(1, newString.length() - 1);
|
||||
for (String string: strings)
|
||||
{
|
||||
bypassPlayers.add(UUID.fromString(string));
|
||||
}
|
||||
}
|
||||
private static ArrayList<String> exportBypassStringList()
|
||||
{
|
||||
ArrayList<String> strings = new ArrayList<String>();
|
||||
for (UUID uuid: bypassPlayers)
|
||||
{
|
||||
strings.add(uuid.toString());
|
||||
}
|
||||
return strings;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static boolean isBorderTimerRunning()
|
||||
@ -526,7 +538,7 @@ public class Config
|
||||
}
|
||||
|
||||
|
||||
private static final int currentCfgVersion = 10;
|
||||
private static final int currentCfgVersion = 11;
|
||||
|
||||
public static void load(WorldBorder master, boolean logIt)
|
||||
{ // load config from file
|
||||
@ -552,7 +564,7 @@ public class Config
|
||||
killPlayer = cfg.getBoolean("player-killed-bad-spawn", false);
|
||||
denyEnderpearl = cfg.getBoolean("deny-enderpearl", true);
|
||||
fillAutosaveFrequency = cfg.getInt("fill-autosave-frequency", 30);
|
||||
bypassPlayers = Collections.synchronizedSet(new LinkedHashSet<String>(cfg.getStringList("bypass-list")));
|
||||
importBypassStringList(cfg.getStringList("bypass-list-uuids"));
|
||||
fillMemoryTolerance = cfg.getInt("fill-memory-tolerance", 500);
|
||||
|
||||
StartBorderTimer();
|
||||
@ -579,6 +591,10 @@ public class Config
|
||||
if (cfgVersion < 10)
|
||||
denyEnderpearl = true;
|
||||
|
||||
// the border bypass list used to be stored as list of names rather than UUIDs; wipe that old list so the data won't be automatically saved back to the config file again
|
||||
if (cfgVersion < 11)
|
||||
cfg.set("bypass-list", null);
|
||||
|
||||
ConfigurationSection worlds = cfg.getConfigurationSection("worlds");
|
||||
if (worlds != null)
|
||||
{
|
||||
@ -654,7 +670,7 @@ public class Config
|
||||
cfg.set("player-killed-bad-spawn", killPlayer);
|
||||
cfg.set("deny-enderpearl", denyEnderpearl);
|
||||
cfg.set("fill-autosave-frequency", fillAutosaveFrequency);
|
||||
cfg.set("bypass-list", new ArrayList<String>(bypassPlayers));
|
||||
cfg.set("bypass-list-uuids", exportBypassStringList());
|
||||
cfg.set("fill-memory-tolerance", fillMemoryTolerance);
|
||||
|
||||
cfg.set("worlds", null);
|
||||
|
49
src/main/java/com/wimbli/WorldBorder/UUID/NameFetcher.java
Normal file
49
src/main/java/com/wimbli/WorldBorder/UUID/NameFetcher.java
Normal file
@ -0,0 +1,49 @@
|
||||
package com.wimbli.WorldBorder.UUID;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
||||
/*
|
||||
* code by evilmidget38
|
||||
* from http://forums.bukkit.org/threads/player-name-uuid-fetcher.250926/
|
||||
*/
|
||||
|
||||
public class NameFetcher implements Callable<Map<UUID, String>> {
|
||||
private static final String PROFILE_URL = "https://sessionserver.mojang.com/session/minecraft/profile/";
|
||||
private final JSONParser jsonParser = new JSONParser();
|
||||
private final List<UUID> uuids;
|
||||
public NameFetcher(List<UUID> uuids) {
|
||||
this.uuids = ImmutableList.copyOf(uuids);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<UUID, String> call() throws Exception {
|
||||
Map<UUID, String> uuidStringMap = new HashMap<UUID, String>();
|
||||
for (UUID uuid: uuids) {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(PROFILE_URL+uuid.toString().replace("-", "")).openConnection();
|
||||
JSONObject response = (JSONObject) jsonParser.parse(new InputStreamReader(connection.getInputStream()));
|
||||
String name = (String) response.get("name");
|
||||
if (name == null) {
|
||||
continue;
|
||||
}
|
||||
String cause = (String) response.get("cause");
|
||||
String errorMessage = (String) response.get("errorMessage");
|
||||
if (cause != null && cause.length() > 0) {
|
||||
throw new IllegalStateException(errorMessage);
|
||||
}
|
||||
uuidStringMap.put(uuid, name);
|
||||
}
|
||||
return uuidStringMap;
|
||||
}
|
||||
}
|
103
src/main/java/com/wimbli/WorldBorder/UUID/UUIDFetcher.java
Normal file
103
src/main/java/com/wimbli/WorldBorder/UUID/UUIDFetcher.java
Normal file
@ -0,0 +1,103 @@
|
||||
package com.wimbli.WorldBorder.UUID;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.json.simple.JSONArray;
|
||||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
|
||||
/*
|
||||
* code by evilmidget38
|
||||
* from http://forums.bukkit.org/threads/player-name-uuid-fetcher.250926/
|
||||
* slightly modified to fix name case mismatches for single name lookup
|
||||
*/
|
||||
|
||||
public class UUIDFetcher implements Callable<Map<String, UUID>> {
|
||||
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<String> names;
|
||||
private final boolean rateLimiting;
|
||||
|
||||
public UUIDFetcher(List<String> names, boolean rateLimiting) {
|
||||
this.names = ImmutableList.copyOf(names);
|
||||
this.rateLimiting = rateLimiting;
|
||||
}
|
||||
|
||||
public UUIDFetcher(List<String> names) {
|
||||
this(names, true);
|
||||
}
|
||||
|
||||
public Map<String, UUID> call() throws Exception {
|
||||
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
|
||||
int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST);
|
||||
for (int i = 0; i < requests; i++) {
|
||||
HttpURLConnection connection = createConnection();
|
||||
String body = JSONArray.toJSONString(names.subList(i * 100, Math.min((i + 1) * 100, names.size())));
|
||||
writeBody(connection, body);
|
||||
JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream()));
|
||||
for (Object profile : array) {
|
||||
JSONObject jsonProfile = (JSONObject) profile;
|
||||
String id = (String) jsonProfile.get("id");
|
||||
String name = (String) jsonProfile.get("name");
|
||||
UUID uuid = UUIDFetcher.getUUID(id);
|
||||
uuidMap.put(name.toLowerCase(), uuid);
|
||||
}
|
||||
if (rateLimiting && i != requests - 1) {
|
||||
Thread.sleep(100L);
|
||||
}
|
||||
}
|
||||
return uuidMap;
|
||||
}
|
||||
|
||||
private static void writeBody(HttpURLConnection connection, String body) throws Exception {
|
||||
OutputStream stream = connection.getOutputStream();
|
||||
stream.write(body.getBytes());
|
||||
stream.flush();
|
||||
stream.close();
|
||||
}
|
||||
|
||||
private static HttpURLConnection createConnection() throws Exception {
|
||||
URL url = new URL(PROFILE_URL);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setRequestProperty("Content-Type", "application/json");
|
||||
connection.setUseCaches(false);
|
||||
connection.setDoInput(true);
|
||||
connection.setDoOutput(true);
|
||||
return connection;
|
||||
}
|
||||
|
||||
private static UUID getUUID(String id) {
|
||||
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +id.substring(20, 32));
|
||||
}
|
||||
|
||||
public static byte[] toBytes(UUID uuid) {
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
|
||||
byteBuffer.putLong(uuid.getMostSignificantBits());
|
||||
byteBuffer.putLong(uuid.getLeastSignificantBits());
|
||||
return byteBuffer.array();
|
||||
}
|
||||
|
||||
public static UUID fromBytes(byte[] array) {
|
||||
if (array.length != 16) {
|
||||
throw new IllegalArgumentException("Illegal byte array length: " + array.length);
|
||||
}
|
||||
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
|
||||
long mostSignificant = byteBuffer.getLong();
|
||||
long leastSignificant = byteBuffer.getLong();
|
||||
return new UUID(mostSignificant, leastSignificant);
|
||||
}
|
||||
|
||||
public static UUID getUUIDOf(String name) throws Exception {
|
||||
return new UUIDFetcher(Arrays.asList(name)).call().get(name.toLowerCase());
|
||||
}
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
package com.wimbli.WorldBorder.cmd;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.wimbli.WorldBorder.*;
|
||||
import com.wimbli.WorldBorder.UUID.UUIDFetcher;
|
||||
|
||||
|
||||
public class CmdBypass extends WBCmd
|
||||
@ -27,13 +29,15 @@ public class CmdBypass extends WBCmd
|
||||
@Override
|
||||
public void cmdStatus(CommandSender sender)
|
||||
{
|
||||
boolean bypass = Config.isPlayerBypassing(((Player)sender).getName());
|
||||
if (sender instanceof Player)
|
||||
sender.sendMessage(C_HEAD + "Border bypass is currently " + enabledColored(bypass) + C_HEAD + " for you.");
|
||||
if (!(sender instanceof Player))
|
||||
return;
|
||||
|
||||
boolean bypass = Config.isPlayerBypassing(((Player)sender).getUniqueId());
|
||||
sender.sendMessage(C_HEAD + "Border bypass is currently " + enabledColored(bypass) + C_HEAD + " for you.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
||||
public void execute(final CommandSender sender, final Player player, final List<String> params, String worldName)
|
||||
{
|
||||
if (player == null && params.isEmpty())
|
||||
{
|
||||
@ -41,21 +45,56 @@ public class CmdBypass extends WBCmd
|
||||
return;
|
||||
}
|
||||
|
||||
String sPlayer = (params.isEmpty()) ? player.getName() : params.get(0);
|
||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(WorldBorder.plugin, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
final String sPlayer = (params.isEmpty()) ? player.getName() : params.get(0);
|
||||
UUID uPlayer = (params.isEmpty()) ? player.getUniqueId() : null;
|
||||
|
||||
boolean bypassing = !Config.isPlayerBypassing(sPlayer);
|
||||
if (params.size() > 1)
|
||||
bypassing = strAsBool(params.get(1));
|
||||
if (uPlayer == null)
|
||||
{
|
||||
Player p = Bukkit.getPlayer(sPlayer);
|
||||
if (p != null)
|
||||
{
|
||||
uPlayer = p.getUniqueId();
|
||||
}
|
||||
else
|
||||
{
|
||||
// only do UUID lookup using Mojang server if specified player isn't online
|
||||
try
|
||||
{
|
||||
uPlayer = UUIDFetcher.getUUIDOf(sPlayer);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
sendErrorAndHelp(sender, "Failed to look up UUID for the player name you specified. " + ex.getLocalizedMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (uPlayer == null)
|
||||
{
|
||||
sendErrorAndHelp(sender, "Failed to look up UUID for the player name you specified; null value returned.");
|
||||
return;
|
||||
}
|
||||
|
||||
Config.setPlayerBypass(sPlayer, bypassing);
|
||||
boolean bypassing = !Config.isPlayerBypassing(uPlayer);
|
||||
if (params.size() > 1)
|
||||
bypassing = strAsBool(params.get(1));
|
||||
|
||||
Player target = Bukkit.getPlayer(sPlayer);
|
||||
if (target != null && target.isOnline())
|
||||
target.sendMessage("Border bypass is now " + enabledColored(bypassing) + ".");
|
||||
Config.setPlayerBypass(uPlayer, bypassing);
|
||||
|
||||
Config.log("Border bypass for player \"" + sPlayer + "\" is " + (bypassing ? "enabled" : "disabled") +
|
||||
(player != null ? " at the command of player \"" + player.getName() + "\"" : "") + ".");
|
||||
if (player != null && player != target)
|
||||
sender.sendMessage("Border bypass for player \"" + sPlayer + "\" is " + enabledColored(bypassing) + ".");
|
||||
Player target = Bukkit.getPlayer(sPlayer);
|
||||
if (target != null && target.isOnline())
|
||||
target.sendMessage("Border bypass is now " + enabledColored(bypassing) + ".");
|
||||
|
||||
Config.log("Border bypass for player \"" + sPlayer + "\" is " + (bypassing ? "enabled" : "disabled") +
|
||||
(player != null ? " at the command of player \"" + player.getName() + "\"" : "") + ".");
|
||||
if (player != null && player != target)
|
||||
sender.sendMessage("Border bypass for player \"" + sPlayer + "\" is " + enabledColored(bypassing) + ".");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,16 @@
|
||||
package com.wimbli.WorldBorder.cmd;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.*;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.wimbli.WorldBorder.*;
|
||||
import com.wimbli.WorldBorder.UUID.NameFetcher;
|
||||
|
||||
|
||||
public class CmdBypasslist extends WBCmd
|
||||
@ -21,8 +26,34 @@ public class CmdBypasslist extends WBCmd
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(CommandSender sender, Player player, List<String> params, String worldName)
|
||||
public void execute(final CommandSender sender, Player player, List<String> params, String worldName)
|
||||
{
|
||||
sender.sendMessage("Players with border bypass enabled: " + Config.getPlayerBypassList());
|
||||
final ArrayList<UUID> uuids = Config.getPlayerBypassList();
|
||||
if (uuids == null || uuids.isEmpty())
|
||||
{
|
||||
sender.sendMessage("Players with border bypass enabled: <none>");
|
||||
return;
|
||||
}
|
||||
|
||||
Bukkit.getServer().getScheduler().scheduleSyncDelayedTask(WorldBorder.plugin, new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
NameFetcher fetcher = new NameFetcher(uuids);
|
||||
Map<UUID, String> names = fetcher.call();
|
||||
String nameString = names.values().toString();
|
||||
|
||||
sender.sendMessage("Players with border bypass enabled: " + nameString.substring(1, nameString.length() - 1));
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
sendErrorAndHelp(sender, "Failed to look up names for the UUIDs in the border bypass list. " + ex.getLocalizedMessage());
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user