Fixes #748
Fixes #759
This commit is contained in:
Jesse Boyd 2015-11-28 22:46:10 +11:00
parent 7db30590c6
commit 94b0fbb266
23 changed files with 445 additions and 140 deletions

View File

@ -846,7 +846,7 @@ public class PS {
*/ */
@Deprecated @Deprecated
public void sortPlotsByHash(final Plot[] input) { public void sortPlotsByHash(final Plot[] input) {
final List<Plot>[] bucket = new ArrayList[64]; final List<Plot>[] bucket = new ArrayList[32];
for (int i = 0; i < bucket.length; i++) { for (int i = 0; i < bucket.length; i++) {
bucket[i] = new ArrayList<Plot>(); bucket[i] = new ArrayList<Plot>();
} }
@ -856,19 +856,19 @@ public class PS {
maxLength = true; maxLength = true;
for (final Plot i : input) { for (final Plot i : input) {
tmp = MathMan.getPositiveId(i.hashCode()) / placement; tmp = MathMan.getPositiveId(i.hashCode()) / placement;
bucket[tmp & 63].add(i); bucket[tmp & 31].add(i);
if (maxLength && (tmp > 0)) { if (maxLength && (tmp > 0)) {
maxLength = false; maxLength = false;
} }
} }
int a = 0; int a = 0;
for (int b = 0; b < 64; b++) { for (int b = 0; b < 32; b++) {
for (final Plot i : bucket[b]) { for (final Plot i : bucket[b]) {
input[a++] = i; input[a++] = i;
} }
bucket[b].clear(); bucket[b].clear();
} }
placement *= 64; placement *= 32;
} }
} }
@ -1068,8 +1068,8 @@ public class PS {
return strings.toArray(new String[strings.size()]); return strings.toArray(new String[strings.size()]);
} }
private String lastWorld; private volatile String lastWorld;
private Map<PlotId, Plot> lastMap; private volatile Map<PlotId, Plot> lastMap;
/** /**
* Get a map of the plots for a world * Get a map of the plots for a world
@ -1112,12 +1112,9 @@ public class PS {
return null; return null;
} }
lastWorld = world; lastWorld = world;
if (plots.containsKey(world)) { lastMap = plots.get(world);
lastMap = plots.get(world); if (lastMap != null) {
if (lastMap != null) { return lastMap.get(id);
return lastMap.get(id);
}
return null;
} }
return null; return null;
} }

View File

@ -67,7 +67,7 @@ public class Copy extends SubCommand {
C.COMMAND_SYNTAX.send(plr, getUsage()); C.COMMAND_SYNTAX.send(plr, getUsage());
return false; return false;
} }
if (!plot1.getWorld().equals(plot2.getWorld())) { if (!plot1.getWorld().isCompatible(plot2.getWorld())) {
C.PLOTWORLD_INCOMPATIBLE.send(plr); C.PLOTWORLD_INCOMPATIBLE.send(plr);
return false; return false;
} }

View File

@ -34,7 +34,6 @@ import com.intellectualcrafters.plot.util.EconHandler;
import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.MainUtil;
import com.intellectualcrafters.plot.util.Permissions; import com.intellectualcrafters.plot.util.Permissions;
import com.intellectualcrafters.plot.util.TaskManager; import com.intellectualcrafters.plot.util.TaskManager;
import com.intellectualcrafters.plot.util.UUIDHandler;
import com.plotsquared.general.commands.CommandDeclaration; import com.plotsquared.general.commands.CommandDeclaration;
@CommandDeclaration( @CommandDeclaration(

View File

@ -67,7 +67,7 @@ public class Move extends SubCommand {
MainUtil.sendMessage(plr, C.COMMAND_SYNTAX, "/plot copy <X;Z>"); MainUtil.sendMessage(plr, C.COMMAND_SYNTAX, "/plot copy <X;Z>");
return false; return false;
} }
if (!plot1.getWorld().equals(plot2.getWorld())) { if (!plot1.getWorld().isCompatible(plot2.getWorld())) {
C.PLOTWORLD_INCOMPATIBLE.send(plr); C.PLOTWORLD_INCOMPATIBLE.send(plr);
return false; return false;
} }

View File

@ -45,30 +45,32 @@ public class Owner extends SetCommand {
@Override @Override
public boolean set(PlotPlayer plr, Plot plot, String value) { public boolean set(PlotPlayer plr, Plot plot, String value) {
HashSet<Plot> plots = MainUtil.getConnectedPlots(plot); HashSet<Plot> plots = MainUtil.getConnectedPlots(plot);
final PlotPlayer other = UUIDHandler.getPlayer(value);
UUID uuid = null; UUID uuid = null;
if (other == null) { String name = null;
if (Permissions.hasPermission(plr, "plots.admin.command.setowner")) { if (value.length() == 36) {
if ((uuid = UUIDHandler.getUUID(value, null)) == null) { try {
try { uuid = UUID.fromString(value);
uuid = UUID.fromString(value); name = MainUtil.getName(uuid);
} catch (Exception e) {} } catch (Exception e) {}
} } else {
} uuid = UUIDHandler.getUUID(value, null);
} name = UUIDHandler.getName(uuid);
else { name = name == null ? value : name;
other.getUUID();
} }
if (uuid == null) { if (uuid == null) {
MainUtil.sendMessage(plr, C.INVALID_PLAYER, value); C.INVALID_PLAYER.send(plr, value);
return false; return false;
} }
String name = other == null ? MainUtil.getName(uuid) : other.getName();
if (plot.isOwner(uuid)) { if (plot.isOwner(uuid)) {
C.ALREADY_OWNER.send(plr); C.ALREADY_OWNER.send(plr);
return false; return false;
} }
if (other != null && !Permissions.hasPermission(plr, "plots.admin.command.setowner")) { PlotPlayer other = UUIDHandler.getPlayer(uuid);
if (!Permissions.hasPermission(plr, "plots.admin.command.setowner")) {
if (other == null) {
C.INVALID_PLAYER_OFFLINE.send(plr, value);
return false;
}
final int size = plots.size(); final int size = plots.size();
final int currentPlots = (Settings.GLOBAL_LIMIT ? MainUtil.getPlayerPlotCount(other) : MainUtil.getPlayerPlotCount(plot.world, other)) + size; final int currentPlots = (Settings.GLOBAL_LIMIT ? MainUtil.getPlayerPlotCount(other) : MainUtil.getPlayerPlotCount(plot.world, other)) + size;
if (currentPlots > MainUtil.getAllowedPlots(other)) { if (currentPlots > MainUtil.getAllowedPlots(other)) {
@ -76,6 +78,7 @@ public class Owner extends SetCommand {
return false; return false;
} }
} }
plot.setOwner(uuid); plot.setOwner(uuid);
MainUtil.setSign(name, plot); MainUtil.setSign(name, plot);
MainUtil.sendMessage(plr, C.SET_OWNER); MainUtil.sendMessage(plr, C.SET_OWNER);

View File

@ -55,7 +55,7 @@ public class Swap extends SubCommand {
MainUtil.sendMessage(plr, C.COMMAND_SYNTAX, "/plot copy <X;Z>"); MainUtil.sendMessage(plr, C.COMMAND_SYNTAX, "/plot copy <X;Z>");
return false; return false;
} }
if (!plot1.getWorld().equals(plot2.getWorld())) { if (!plot1.getWorld().isCompatible(plot2.getWorld())) {
C.PLOTWORLD_INCOMPATIBLE.send(plr); C.PLOTWORLD_INCOMPATIBLE.send(plr);
return false; return false;
} }

View File

@ -331,7 +331,7 @@ public class list extends SubCommand {
} }
} }
if (sort) { if (sort) {
plots = PS.get().sortPlots(plots, SortType.DISTANCE_FROM_ORIGIN, world); plots = PS.get().sortPlots(plots, SortType.CREATION_DATE_TIMESTAMP, world);
} }
if (page < 0) { if (page < 0) {
page = 0; page = 0;

View File

@ -375,6 +375,7 @@ public enum C {
*/ */
INVALID_PLAYER_WAIT("$2Player not found: $1%s$2, fetching it. Try again soon.", "Errors"), INVALID_PLAYER_WAIT("$2Player not found: $1%s$2, fetching it. Try again soon.", "Errors"),
INVALID_PLAYER("$2Player not found: $1%s.", "Errors"), INVALID_PLAYER("$2Player not found: $1%s.", "Errors"),
INVALID_PLAYER_OFFLINE("$2The player must be online: $1%s.", "Errors"),
// SETTINGS_PASTE_UPLOADED("$2settings.yml was uploaded to: $1%url%", "Paste"), // SETTINGS_PASTE_UPLOADED("$2settings.yml was uploaded to: $1%url%", "Paste"),
// LATEST_LOG_UPLOADED("$2latest.log was uploaded to: $1%url%", "Paste"), // LATEST_LOG_UPLOADED("$2latest.log was uploaded to: $1%url%", "Paste"),
DEBUG_REPORT_CREATED("$1Uploaded a full debug to: $1%url%", "Paste"), DEBUG_REPORT_CREATED("$1Uploaded a full debug to: $1%url%", "Paste"),

View File

@ -1193,6 +1193,9 @@ public class SQLManager implements AbstractDB {
@Override @Override
public void deleteSettings(final Plot plot) { public void deleteSettings(final Plot plot) {
if (plot.settings == null) {
return;
}
addPlotTask(plot, new UniqueStatement("delete_plot_settings") { addPlotTask(plot, new UniqueStatement("delete_plot_settings") {
@Override @Override
public void set(final PreparedStatement stmt) throws SQLException { public void set(final PreparedStatement stmt) throws SQLException {
@ -1301,7 +1304,6 @@ public class SQLManager implements AbstractDB {
*/ */
@Override @Override
public void delete(final Plot plot) { public void delete(final Plot plot) {
PS.get().removePlot(plot.world, plot.id, false);
deleteSettings(plot); deleteSettings(plot);
deleteDenied(plot); deleteDenied(plot);
deleteHelpers(plot); deleteHelpers(plot);
@ -1736,7 +1738,7 @@ public class SQLManager implements AbstractDB {
map = new ConcurrentHashMap<PlotId, Plot>(); map = new ConcurrentHashMap<PlotId, Plot>();
newplots.put(plot.world, map); newplots.put(plot.world, map);
} }
newplots.get(plot.world).put(plot.id, plot); map.put(plot.id, plot);
} }
} }
boolean invalidPlot = false; boolean invalidPlot = false;

View File

@ -120,15 +120,19 @@ public class FlagManager {
} }
public static Flag getSettingFlag(final String world, final PlotSettings settings, final String id) { public static Flag getSettingFlag(final String world, final PlotSettings settings, final String id) {
System.out.print("GETTIGN FLAG!! " + (settings.flags.size() == 0) + " | " + ((settings.flags.get(id)) == null));
Flag flag; Flag flag;
if ((settings.flags.size() == 0) || ((flag = settings.flags.get(id)) == null)) { if ((settings.flags.size() == 0) || ((flag = settings.flags.get(id)) == null)) {
final PlotWorld plotworld = PS.get().getPlotWorld(world); final PlotWorld plotworld = PS.get().getPlotWorld(world);
if (plotworld == null) { if (plotworld == null) {
System.out.print("pw is nykl");
return null; return null;
} }
if (plotworld.DEFAULT_FLAGS.size() == 0) { if (plotworld.DEFAULT_FLAGS.size() == 0) {
System.out.print("no default flags");
return null; return null;
} }
System.out.print("DEFAULT_FLAGS: " + plotworld.DEFAULT_FLAGS + " | " + plotworld.DEFAULT_FLAGS.get(id));
return plotworld.DEFAULT_FLAGS.get(id); return plotworld.DEFAULT_FLAGS.get(id);
} }
return flag; return flag;

View File

@ -28,9 +28,21 @@ public class ClassicPlotManager extends SquarePlotManager {
return true; return true;
} }
case "all": { case "all": {
setAll(plotworld, plotid, blocks);
return true;
}
case "air": {
setAir(plotworld, plotid, blocks); setAir(plotworld, plotid, blocks);
return true; return true;
} }
case "main": {
setMain(plotworld, plotid, blocks);
return true;
}
case "middle": {
setMiddle(plotworld, plotid, blocks);
return true;
}
case "outline": { case "outline": {
setOutline(plotworld, plotid, blocks); setOutline(plotworld, plotid, blocks);
return true; return true;
@ -67,6 +79,20 @@ public class ClassicPlotManager extends SquarePlotManager {
return true; return true;
} }
public boolean setAll(final PlotWorld plotworld, final PlotId plotid, final PlotBlock[] blocks) {
Plot plot = MainUtil.getPlotAbs(plotworld.worldname, plotid);
if (!plot.isBasePlot()) {
return false;
}
final ClassicPlotWorld dpw = (ClassicPlotWorld) plotworld;
for (RegionWrapper region : MainUtil.getRegions(plot)) {
Location pos1 = new Location(plot.world, region.minX, 1, region.minZ);
Location pos2 = new Location(plot.world, region.maxX, 255, region.maxZ);
MainUtil.setCuboidAsync(plotworld.worldname, pos1, pos2, blocks);
}
return true;
}
public boolean setAir(final PlotWorld plotworld, final PlotId plotid, final PlotBlock[] blocks) { public boolean setAir(final PlotWorld plotworld, final PlotId plotid, final PlotBlock[] blocks) {
Plot plot = MainUtil.getPlotAbs(plotworld.worldname, plotid); Plot plot = MainUtil.getPlotAbs(plotworld.worldname, plotid);
if (!plot.isBasePlot()) { if (!plot.isBasePlot()) {
@ -81,6 +107,31 @@ public class ClassicPlotManager extends SquarePlotManager {
return true; return true;
} }
public boolean setMain(final PlotWorld plotworld, final PlotId plotid, final PlotBlock[] blocks) {
Plot plot = MainUtil.getPlotAbs(plotworld.worldname, plotid);
if (!plot.isBasePlot()) {
return false;
}
final ClassicPlotWorld dpw = (ClassicPlotWorld) plotworld;
for (RegionWrapper region : MainUtil.getRegions(plot)) {
Location pos1 = new Location(plot.world, region.minX, 1, region.minZ);
Location pos2 = new Location(plot.world, region.maxX, dpw.PLOT_HEIGHT - 1, region.maxZ);
MainUtil.setCuboidAsync(plotworld.worldname, pos1, pos2, blocks);
}
return true;
}
public boolean setMiddle(final PlotWorld plotworld, final PlotId plotid, final PlotBlock[] blocks) {
Plot plot = MainUtil.getPlotAbs(plotworld.worldname, plotid);
if (!plot.isBasePlot()) {
return false;
}
Location[] corners = plot.getCorners();
final ClassicPlotWorld dpw = (ClassicPlotWorld) plotworld;
SetBlockQueue.setBlock(plotworld.worldname, (corners[0].getX() + corners[1].getX()) / 2, dpw.PLOT_HEIGHT, (corners[0].getZ() + corners[1].getZ()) / 2, blocks[0]);
return true;
}
public boolean setOutline(final PlotWorld plotworld, final PlotId plotid, final PlotBlock[] blocks) { public boolean setOutline(final PlotWorld plotworld, final PlotId plotid, final PlotBlock[] blocks) {
final ClassicPlotWorld dpw = (ClassicPlotWorld) plotworld; final ClassicPlotWorld dpw = (ClassicPlotWorld) plotworld;
if (dpw.ROAD_WIDTH == 0) { if (dpw.ROAD_WIDTH == 0) {
@ -368,7 +419,7 @@ public class ClassicPlotManager extends SquarePlotManager {
@Override @Override
public String[] getPlotComponents(final PlotWorld plotworld, final PlotId plotid) { public String[] getPlotComponents(final PlotWorld plotworld, final PlotId plotid) {
return new String[] { "floor", "wall", "border", "all", "outline" }; return new String[] { "main", "floor", "air", "all", "border", "wall", "outline", "middle" };
} }
/** /**

View File

@ -28,6 +28,7 @@ import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.object.PlotBlock; import com.intellectualcrafters.plot.object.PlotBlock;
import com.intellectualcrafters.plot.object.PlotLoc; import com.intellectualcrafters.plot.object.PlotLoc;
import com.intellectualcrafters.plot.object.PlotWorld;
import com.intellectualcrafters.plot.object.schematic.PlotItem; import com.intellectualcrafters.plot.object.schematic.PlotItem;
import com.intellectualcrafters.plot.util.SchematicHandler; import com.intellectualcrafters.plot.util.SchematicHandler;
import com.intellectualcrafters.plot.util.SchematicHandler.Dimension; import com.intellectualcrafters.plot.util.SchematicHandler.Dimension;
@ -72,6 +73,14 @@ public class HybridPlotWorld extends ClassicPlotWorld {
} }
} }
@Override
public boolean isCompatible(PlotWorld plotworld) {
if (plotworld == null || !(plotworld instanceof SquarePlotWorld)) {
return false;
}
return ((ClassicPlotWorld) plotworld).PLOT_WIDTH == PLOT_WIDTH;
}
public void setupSchematics() { public void setupSchematics() {
G_SCH_DATA = new HashMap<>(); G_SCH_DATA = new HashMap<>();
G_SCH = new HashMap<>(); G_SCH = new HashMap<>();

View File

@ -85,6 +85,10 @@ public class Location implements Cloneable, Comparable<Location> {
return MainUtil.getPlot(this); return MainUtil.getPlot(this);
} }
public ChunkLoc getChunkLoc() {
return new ChunkLoc(x >> 4, z >> 4);
}
public void setWorld(final String world) { public void setWorld(final String world) {
this.world = world; this.world = world;
built = false; built = false;

View File

@ -416,7 +416,6 @@ public class Plot {
*/ */
private Plot origin; private Plot origin;
/** /**
* The base plot is an arbitrary but specific connected plot. It is useful for the following:<br> * The base plot is an arbitrary but specific connected plot. It is useful for the following:<br>
* - Merged plots need to be treated as a single plot for most purposes<br> * - Merged plots need to be treated as a single plot for most purposes<br>
@ -721,7 +720,7 @@ public class Plot {
*/ */
public double getAverageRating() { public double getAverageRating() {
double sum = 0; double sum = 0;
final Collection<Rating> ratings = getBasePlot(false).getRatings().values(); final Collection<Rating> ratings = getRatings().values();
for (final Rating rating : ratings) { for (final Rating rating : ratings) {
sum += rating.getAverageRating(); sum += rating.getAverageRating();
} }

View File

@ -237,9 +237,9 @@ public class PlotHandler {
return false; return false;
} }
for (Plot current : MainUtil.getConnectedPlots(plot)) { for (Plot current : MainUtil.getConnectedPlots(plot)) {
current.settings = null;
PS.get().removePlot(current.world, current.id, true); PS.get().removePlot(current.world, current.id, true);
DBFunc.delete(current); DBFunc.delete(current);
current.settings = null;
} }
return true; return true;
} }

View File

@ -126,6 +126,10 @@ public abstract class PlotWorld {
return true; return true;
} }
public boolean isCompatible(PlotWorld plotworld) {
return equals(plotworld);
}
/** /**
* When a world is created, the following method will be called for each * When a world is created, the following method will be called for each
* *

View File

@ -20,6 +20,7 @@
//////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////
package com.intellectualcrafters.plot.util; package com.intellectualcrafters.plot.util;
import java.nio.charset.StandardCharsets;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -36,6 +37,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import com.google.common.collect.BiMap;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.Settings; import com.intellectualcrafters.plot.config.Settings;
@ -56,6 +58,7 @@ import com.intellectualcrafters.plot.object.PlotWorld;
import com.intellectualcrafters.plot.object.PseudoRandom; import com.intellectualcrafters.plot.object.PseudoRandom;
import com.intellectualcrafters.plot.object.RegionWrapper; import com.intellectualcrafters.plot.object.RegionWrapper;
import com.intellectualcrafters.plot.object.RunnableVal; import com.intellectualcrafters.plot.object.RunnableVal;
import com.intellectualcrafters.plot.object.StringWrapper;
import com.plotsquared.listener.PlotListener; import com.plotsquared.listener.PlotListener;
/** /**
@ -1427,7 +1430,9 @@ public class MainUtil {
final HashSet<RegionWrapper> regions = getRegions(plot); final HashSet<RegionWrapper> regions = getRegions(plot);
final HashSet<Plot> plots = getConnectedPlots(plot); final HashSet<Plot> plots = getConnectedPlots(plot);
final ArrayDeque<Plot> queue = new ArrayDeque<>(plots); final ArrayDeque<Plot> queue = new ArrayDeque<>(plots);
removeSign(plot); if (isDelete) {
removeSign(plot);
}
MainUtil.unlinkPlot(plot, true, !isDelete); MainUtil.unlinkPlot(plot, true, !isDelete);
final PlotManager manager = PS.get().getPlotManager(plot.world); final PlotManager manager = PS.get().getPlotManager(plot.world);
final PlotWorld plotworld = PS.get().getPlotWorld(plot.world); final PlotWorld plotworld = PS.get().getPlotWorld(plot.world);
@ -1724,6 +1729,12 @@ public class MainUtil {
return true; return true;
} }
/**
* Check if a plot can be claimed
* @param player
* @param plot
* @return
*/
public static boolean canClaim(final PlotPlayer player, final Plot plot) { public static boolean canClaim(final PlotPlayer player, final Plot plot) {
if (plot == null) { if (plot == null) {
return false; return false;
@ -1736,7 +1747,63 @@ public class MainUtil {
} }
} }
} }
return plot.owner == null; return guessOwner(plot) == null;
}
/**
* Try to guess who the plot owner is:
* - Checks cache
* - Checks sign text
* @param plot
* @return
*/
public static UUID guessOwner(Plot plot) {
if (plot.owner != null) {
return plot.owner;
}
PlotWorld pw = plot.getWorld();
if (!pw.ALLOW_SIGNS) {
return null;
}
Location loc = plot.getManager().getSignLoc(pw, plot);
ChunkManager.manager.loadChunk(loc.getWorld(), loc.getChunkLoc(), false);
String[] lines = BlockManager.manager.getSign(loc);
if (lines == null) {
return null;
}
loop:
for (int i = 4; i > 0; i--) {
String caption = C.valueOf("OWNER_SIGN_LINE_" + i).s();
int index = caption.indexOf("%plr%");
if (index == -1) {
continue;
}
String name = lines[i - 1].substring(index);
if (name.length() == 0) {
return null;
}
UUID owner = UUIDHandler.getUUID(name, null);
if (owner != null) {
plot.owner = owner;
break;
}
if (lines[i - 1].length() == 15) {
BiMap<StringWrapper, UUID> map = UUIDHandler.getUuidMap();
for (Entry<StringWrapper, UUID> entry : map.entrySet()) {
String key = entry.getKey().value;
if (key.length() > name.length() && key.startsWith(name)) {
plot.owner = entry.getValue();
break loop;
}
}
}
plot.owner = UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8));
break;
}
if (plot.owner != null) {
plot.create();
}
return plot.owner;
} }
public static boolean isUnowned(final String world, final PlotId pos1, final PlotId pos2) { public static boolean isUnowned(final String world, final PlotId pos1, final PlotId pos2) {

View File

@ -132,17 +132,21 @@ public abstract class UUIDHandlerImplementation {
} }
try { try {
final UUID offline = uuidMap.put(name, uuid); final UUID offline = uuidMap.put(name, uuid);
if ((offline != null) && !offline.equals(uuid)) { if (offline != null) {
final Set<Plot> plots = PS.get().getPlots(offline); if (!offline.equals(uuid)) {
if (plots.size() > 0) { final Set<Plot> plots = PS.get().getPlots(offline);
for (final Plot plot : PS.get().getPlots(offline)) { if (plots.size() > 0) {
plot.owner = uuid; for (final Plot plot : PS.get().getPlots(offline)) {
plot.owner = uuid;
}
DBFunc.replaceUUID(offline, uuid);
PS.debug("&cDetected invalid UUID stored for (1): " + name.value);
PS.debug("&7 - Did you recently switch to online-mode storage without running `uuidconvert`?");
PS.debug("&6PlotSquared will update incorrect entries when the user logs in, or you can reconstruct your database.");
} }
DBFunc.replaceUUID(offline, uuid); return true;
PS.debug("&cDetected invalid UUID stored for (1): " + name.value);
PS.debug("&7 - Did you recently switch to online-mode storage without running `uuidconvert`?");
PS.debug("&6PlotSquared will update incorrect entries when the user logs in, or you can reconstruct your database.");
} }
return false;
} }
} catch (final Exception e) { } catch (final Exception e) {
final BiMap<UUID, StringWrapper> inverse = uuidMap.inverse(); final BiMap<UUID, StringWrapper> inverse = uuidMap.inverse();

View File

@ -0,0 +1,44 @@
package com.intellectualcrafters.plot.uuid;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayDeque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
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 ArrayDeque<UUID> uuids;
public NameFetcher(List<UUID> uuids) {
this.uuids = new ArrayDeque<>(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;
}
}

View File

@ -0,0 +1,102 @@
package com.intellectualcrafters.plot.uuid;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Callable;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import com.google.common.collect.ImmutableList;
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);
}
@Override
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, 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);
}
}

View File

@ -1012,10 +1012,10 @@ public class BukkitChunkManager extends ChunkManager {
} }
private void count(final int[] count, final Entity entity) { private void count(final int[] count, final Entity entity) {
count[0]++;
switch (entity.getType()) { switch (entity.getType()) {
case PLAYER: { case PLAYER: {
// not valid // not valid
return;
} }
case SMALL_FIREBALL: case SMALL_FIREBALL:
case FIREBALL: case FIREBALL:
@ -1118,6 +1118,7 @@ public class BukkitChunkManager extends ChunkManager {
} }
} }
} }
count[0]++;
} }
@Override @Override

View File

@ -1,22 +1,23 @@
package com.plotsquared.bukkit.uuid; package com.plotsquared.bukkit.uuid;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.UUID; import java.util.UUID;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import com.google.common.collect.HashBiMap; import com.google.common.collect.HashBiMap;
import com.intellectualcrafters.json.JSONObject;
import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.PS;
import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.C;
import com.intellectualcrafters.plot.config.Settings; import com.intellectualcrafters.plot.config.Settings;
@ -31,6 +32,11 @@ import com.intellectualcrafters.plot.uuid.UUIDWrapper;
public class SQLUUIDHandler extends UUIDHandlerImplementation { public class SQLUUIDHandler extends UUIDHandlerImplementation {
final String PROFILE_URL = "https://sessionserver.mojang.com/session/minecraft/profile/";
final int MAX_REQUESTS = 500;
final int INTERVAL = 12000;
final JSONParser jsonParser = new JSONParser();
public SQLUUIDHandler(final UUIDWrapper wrapper) { public SQLUUIDHandler(final UUIDWrapper wrapper) {
super(wrapper); super(wrapper);
_sqLite = new SQLite("./plugins/PlotSquared/usercache.db"); _sqLite = new SQLite("./plugins/PlotSquared/usercache.db");
@ -89,7 +95,7 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation {
add(new StringWrapper("*"), DBFunc.everyone); add(new StringWrapper("*"), DBFunc.everyone);
// This should be called as long as there are some unknown plots // This should be called as long as there are some unknown plots
final List<UUID> toFetch = new ArrayList<>(); final ArrayDeque<UUID> toFetch = new ArrayDeque<>();
for (final UUID u : UUIDHandler.getAllUUIDS()) { for (final UUID u : UUIDHandler.getAllUUIDS()) {
if (!uuidExists(u)) { if (!uuidExists(u)) {
toFetch.add(u); toFetch.add(u);
@ -113,49 +119,80 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation {
} }
return; return;
} }
if (!Settings.OFFLINE_MODE) {
PS.debug(C.PREFIX.s() + "&cWill fetch &6" + toFetch.size() + "&c from mojang!"); TaskManager.runTaskAsync(new Runnable() {
int i = 0; @Override
final Iterator<UUID> iterator = toFetch.iterator(); public void run() {
while (iterator.hasNext()) {
final StringBuilder url = new StringBuilder("http://api.intellectualsites.com/uuid/?user=");
final List<UUID> currentIteration = new ArrayList<>();
while ((i++ <= 15) && iterator.hasNext()) {
final UUID _uuid = iterator.next();
url.append(_uuid.toString());
if (iterator.hasNext()) {
url.append(",");
}
currentIteration.add(_uuid);
}
PS.debug(C.PREFIX.s() + "&cWill attempt to fetch &6" + currentIteration.size() + "&c uuids from: &6" + url.toString());
try { try {
final HttpURLConnection connection = (HttpURLConnection) new URL(url.toString()).openConnection(); if (toFetch.size() == 0) {
connection.setRequestProperty("User-Agent", "Mozilla/5.0"); if (whenDone != null) {
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); whenDone.run();
String line;
final StringBuilder rawJSON = new StringBuilder();
while ((line = reader.readLine()) != null) {
rawJSON.append(line);
}
reader.close();
final JSONObject object = new JSONObject(rawJSON.toString());
for (final UUID _u : currentIteration) {
final Object o = object.getJSONObject(_u.toString().replace("-", "")).get("username");
if ((o == null) || !(o instanceof String)) {
continue;
} }
add(new StringWrapper(o.toString()), _u); return;
} }
} catch (final Exception e) { for (int i = 0; i < Math.min(500, toFetch.size()); i++) {
UUID uuid = toFetch.pop();
HttpURLConnection connection = (HttpURLConnection) new URL(PROFILE_URL + uuid.toString().replace("-", "")).openConnection();
InputStreamReader reader = new InputStreamReader(connection.getInputStream());
JSONObject response = (JSONObject) jsonParser.parse(reader);
String name = (String) response.get("name");
if (name != null) {
add(new StringWrapper(name), uuid);
}
}
} catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
i = 0; TaskManager.runTaskLaterAsync(this, INTERVAL);
} }
} });
if (whenDone != null) { /*
whenDone.run(); * This API is no longer accessible.
} */
// if (!Settings.OFFLINE_MODE) {
// PS.debug(C.PREFIX.s() + "&cWill fetch &6" + toFetch.size() + "&c from mojang!");
//
// int i = 0;
// final Iterator<UUID> iterator = toFetch.iterator();
// while (iterator.hasNext()) {
// final StringBuilder url = new StringBuilder("http://api.intellectualsites.com/uuid/?user=");
// final List<UUID> currentIteration = new ArrayList<>();
// while ((i++ <= 15) && iterator.hasNext()) {
// final UUID _uuid = iterator.next();
// url.append(_uuid.toString());
// if (iterator.hasNext()) {
// url.append(",");
// }
// currentIteration.add(_uuid);
// }
// PS.debug(C.PREFIX.s() + "&cWill attempt to fetch &6" + currentIteration.size() + "&c uuids from: &6" + url.toString());
// try {
// final HttpURLConnection connection = (HttpURLConnection) new URL(url.toString()).openConnection();
// connection.setRequestProperty("User-Agent", "Mozilla/5.0");
// final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
// String line;
// final StringBuilder rawJSON = new StringBuilder();
// while ((line = reader.readLine()) != null) {
// rawJSON.append(line);
// }
// reader.close();
// final JSONObject object = new JSONObject(rawJSON.toString());
// for (final UUID _u : currentIteration) {
// final Object o = object.getJSONObject(_u.toString().replace("-", "")).get("username");
// if ((o == null) || !(o instanceof String)) {
// continue;
// }
// add(new StringWrapper(o.toString()), _u);
// }
// } catch (final Exception e) {
// e.printStackTrace();
// }
// i = 0;
// }
// }
// if (whenDone != null) {
// whenDone.run();
// }
} }
}); });
} catch (final SQLException e) { } catch (final SQLException e) {
@ -169,24 +206,31 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation {
@Override @Override
public void fetchUUID(final String name, final RunnableVal<UUID> ifFetch) { public void fetchUUID(final String name, final RunnableVal<UUID> ifFetch) {
PS.debug(C.PREFIX.s() + "UUID for '" + name + "' was null. We'll cache this from the mojang servers!"); PS.debug(C.PREFIX.s() + "UUID for '" + name + "' was null. We'll cache this from the mojang servers!");
if (ifFetch == null) {
return;
}
TaskManager.runTaskAsync(new Runnable() { TaskManager.runTaskAsync(new Runnable() {
@Override @Override
public void run() { public void run() {
final String url = "http://api.intellectualsites.com/uuid/?user=" + name;
try { try {
final HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(); URL url = new URL(PROFILE_URL);
connection.setRequestProperty("User-Agent", "Mozilla/5.0"); HttpURLConnection connection = (HttpURLConnection) url.openConnection();
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); connection.setRequestMethod("POST");
String line; connection.setRequestProperty("Content-Type", "application/json");
final StringBuilder rawJSON = new StringBuilder(); connection.setUseCaches(false);
while ((line = reader.readLine()) != null) { connection.setDoInput(true);
rawJSON.append(line); connection.setDoOutput(true);
} String body = JSONArray.toJSONString(Arrays.asList(name));
reader.close(); OutputStream stream = connection.getOutputStream();
final JSONObject object = new JSONObject(rawJSON.toString()); stream.write(body.getBytes());
ifFetch.value = UUID.fromString(object.getJSONObject(name).getString("dashed")); stream.flush();
add(new StringWrapper(name), ifFetch.value); stream.close();
} catch (final IOException e) { JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream()));
JSONObject jsonProfile = (JSONObject) array.get(0);
String id = (String) jsonProfile.get("id");
String name = (String) jsonProfile.get("name");
ifFetch.value = UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32));
} catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
TaskManager.runTask(ifFetch); TaskManager.runTask(ifFetch);
@ -212,7 +256,7 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation {
@Override @Override
public void run() { public void run() {
try { try {
final PreparedStatement statement = getConnection().prepareStatement("INSERT INTO usercache (`uuid`, `username`) VALUES(?, ?)"); final PreparedStatement statement = getConnection().prepareStatement("REPLACE INTO usercache (`uuid`, `username`) VALUES(?, ?)");
statement.setString(1, uuid.toString()); statement.setString(1, uuid.toString());
statement.setString(2, name.toString()); statement.setString(2, name.toString());
statement.execute(); statement.execute();
@ -228,38 +272,8 @@ public class SQLUUIDHandler extends UUIDHandlerImplementation {
} }
/** /**
* This isn't used as any UUID that is unknown is bulk cached (in lots of 16) * This is useful for name changes
* @param uuid
* @return
*/ */
@Deprecated
public String getName__unused__(final UUID uuid) {
PS.debug(C.PREFIX.s() + "Name for '" + uuid + "' was null. We'll cache this from the mojang servers!");
TaskManager.runTaskAsync(new Runnable() {
@Override
public void run() {
final String url = "http://api.intellectualsites.com/uuid/?user=" + uuid;
try {
final HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
final StringBuilder rawJSON = new StringBuilder();
while ((line = reader.readLine()) != null) {
rawJSON.append(line);
}
reader.close();
final JSONObject object = new JSONObject(rawJSON.toString());
final String username = object.getJSONObject(uuid.toString().replace("-", "")).getString("username");
add(new StringWrapper(username), uuid);
} catch (final IOException e) {
e.printStackTrace();
}
}
});
return null;
}
@Override @Override
public void rename(final UUID uuid, final StringWrapper name) { public void rename(final UUID uuid, final StringWrapper name) {
super.rename(uuid, name); super.rename(uuid, name);

Binary file not shown.