mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2025-06-29 20:24:43 +02:00
Move all files! Hahah
This commit is contained in:
@ -0,0 +1,76 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.PlotBlock;
|
||||
import com.intellectualcrafters.plot.object.schematic.PlotItem;
|
||||
|
||||
public abstract class BlockManager {
|
||||
public static BlockManager manager;
|
||||
|
||||
public abstract boolean isBlockSolid(PlotBlock block);
|
||||
|
||||
public abstract StringComparison<PlotBlock>.ComparisonResult getClosestBlock(String name);
|
||||
|
||||
public abstract String getClosestMatchingName(PlotBlock block);
|
||||
|
||||
public abstract String[] getBiomeList();
|
||||
|
||||
public abstract boolean addItems(String world, PlotItem items);
|
||||
|
||||
public abstract int getBiomeFromString(String biome);
|
||||
|
||||
public abstract int getBlockIdFromString(String block);
|
||||
|
||||
public abstract int getHeighestBlock(Location loc);
|
||||
|
||||
public abstract String getBiome(Location loc);
|
||||
|
||||
public abstract Location getSpawn(String world);
|
||||
|
||||
public abstract String[] getSign(Location loc);
|
||||
|
||||
public abstract boolean isWorld(String world);
|
||||
|
||||
public abstract void functionSetBlocks(String worldname, int[] x, int[] y, int[] z, int[] id, byte[] data);
|
||||
|
||||
public abstract void functionSetSign(String worldname, int x, int y, int z, String[] lines);
|
||||
|
||||
public abstract void functionSetBlock(String worldname, int x, int y, int z, int id, byte data);
|
||||
|
||||
public abstract void functionSetBiomes(final String worldname, final int[] x, final int z[], final int[] biome);
|
||||
|
||||
public static void setBiomes(final String worldname, final int[] x, final int z[], final int[] biome) {
|
||||
manager.functionSetBiomes(worldname, x, z, biome);
|
||||
}
|
||||
|
||||
public static void setBlocks(final String worldname, final int[] x, final int y[], final int z[], final PlotBlock[][] blocks) {
|
||||
final int[] id = new int[blocks.length];
|
||||
final byte[] data = new byte[blocks.length];
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
final PlotBlock[] current = blocks[i];
|
||||
final int n = MainUtil.random.random(current.length);
|
||||
id[i] = current[n].id;
|
||||
data[i] = current[n].data;
|
||||
}
|
||||
setBlocks(worldname, x, y, z, id, data);
|
||||
}
|
||||
|
||||
public static void setBlocks(final String worldname, final int[] x, final int y[], final int z[], final PlotBlock[] blocks) {
|
||||
final int[] id = new int[blocks.length];
|
||||
final byte[] data = new byte[blocks.length];
|
||||
for (int i = 0; i < blocks.length; i++) {
|
||||
final PlotBlock current = blocks[i];
|
||||
id[i] = current.id;
|
||||
data[i] = current.data;
|
||||
}
|
||||
setBlocks(worldname, x, y, z, id, data);
|
||||
}
|
||||
|
||||
public static void setSign(final String worldname, final int x, final int y, final int z, final String[] lines) {
|
||||
manager.functionSetSign(worldname, x, y, z, lines);
|
||||
}
|
||||
|
||||
public static void setBlocks(final String worldname, final int[] x, final int[] y, final int[] z, final int[] id, final byte[] data) {
|
||||
manager.functionSetBlocks(worldname, x, y, z, id, data);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
|
||||
public abstract class BlockUpdateUtil {
|
||||
public static BlockUpdateUtil setBlockManager = null;
|
||||
|
||||
public abstract void update(String worldname, Collection<ChunkLoc> chunkLocs);
|
||||
}
|
@ -0,0 +1,264 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
|
||||
import com.intellectualcrafters.jnbt.ByteArrayTag;
|
||||
import com.intellectualcrafters.jnbt.CompoundTag;
|
||||
import com.intellectualcrafters.jnbt.IntTag;
|
||||
import com.intellectualcrafters.jnbt.ListTag;
|
||||
import com.intellectualcrafters.jnbt.ShortTag;
|
||||
import com.intellectualcrafters.jnbt.StringTag;
|
||||
import com.intellectualcrafters.jnbt.Tag;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.schematic.StateWrapper;
|
||||
|
||||
/**
|
||||
* Schematic Handler
|
||||
*
|
||||
* @author Citymonstret
|
||||
* @author Empire92
|
||||
*/
|
||||
public class BukkitSchematicHandler extends SchematicHandler {
|
||||
|
||||
@Override
|
||||
public CompoundTag getCompoundTag(final String world, final Location pos1, final Location pos2) {
|
||||
// loading chunks
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
try {
|
||||
for (i = (pos1.getX() / 16) * 16; i < (16 + ((pos2.getX() / 16) * 16)); i += 16) {
|
||||
for (j = (pos1.getZ() / 16) * 16; j < (16 + ((pos2.getZ() / 16) * 16)); j += 16) {
|
||||
boolean result = ChunkManager.manager.loadChunk(world, new ChunkLoc(i, j));
|
||||
if (!result) {
|
||||
PS.log("&cIllegal selection. Cannot save non-existent chunk at " + (i / 16) + ", " + (j / 16));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
PS.log("&cIllegal selection. Cannot save corrupt chunk at " + (i / 16) + ", " + (j / 16));
|
||||
return null;
|
||||
}
|
||||
final int width = (pos2.getX() - pos1.getX()) + 1;
|
||||
final int height = (pos2.getY() - pos1.getY()) + 1;
|
||||
final int length = (pos2.getZ() - pos1.getZ()) + 1;
|
||||
final HashMap<String, Tag> schematic = new HashMap<>();
|
||||
schematic.put("Width", new ShortTag("Width", (short) width));
|
||||
schematic.put("Length", new ShortTag("Length", (short) length));
|
||||
schematic.put("Height", new ShortTag("Height", (short) height));
|
||||
schematic.put("Materials", new StringTag("Materials", "Alpha"));
|
||||
schematic.put("WEOriginX", new IntTag("WEOriginX", 0));
|
||||
schematic.put("WEOriginY", new IntTag("WEOriginY", 0));
|
||||
schematic.put("WEOriginZ", new IntTag("WEOriginZ", 0));
|
||||
schematic.put("WEOffsetX", new IntTag("WEOffsetX", 0));
|
||||
schematic.put("WEOffsetY", new IntTag("WEOffsetY", 0));
|
||||
schematic.put("WEOffsetZ", new IntTag("WEOffsetZ", 0));
|
||||
final byte[] blocks = new byte[width * height * length];
|
||||
byte[] addBlocks = null;
|
||||
final byte[] blockData = new byte[width * height * length];
|
||||
final int sx = pos1.getX();
|
||||
pos2.getX();
|
||||
final int sz = pos1.getZ();
|
||||
pos2.getZ();
|
||||
final int sy = pos1.getY();
|
||||
pos2.getY();
|
||||
|
||||
List<Tag> tileEntities = new ArrayList<Tag>();
|
||||
|
||||
World worldObj = Bukkit.getWorld(world);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
int i1 = (y * width * length);
|
||||
for (int z = 0; z < length; z++) {
|
||||
int i2 = i1 + (z * width);
|
||||
for (int x = 0; x < width; x++) {
|
||||
final int index = i2 + x;
|
||||
Block block = worldObj.getBlockAt(sx + x, sy + y, sz + z);
|
||||
int id = block.getTypeId();
|
||||
switch(id) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 24:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 121:
|
||||
case 122:
|
||||
case 129:
|
||||
case 133:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192: {
|
||||
break;
|
||||
}
|
||||
case 54:
|
||||
case 130:
|
||||
case 142:
|
||||
case 27:
|
||||
case 137:
|
||||
case 52:
|
||||
case 154:
|
||||
case 84:
|
||||
case 25:
|
||||
case 144:
|
||||
case 138:
|
||||
case 176:
|
||||
case 177:
|
||||
case 63:
|
||||
case 68:
|
||||
case 323:
|
||||
case 117:
|
||||
case 116:
|
||||
case 28:
|
||||
case 66:
|
||||
case 157:
|
||||
case 61:
|
||||
case 62:
|
||||
case 140:
|
||||
case 146:
|
||||
case 149:
|
||||
case 150:
|
||||
case 158:
|
||||
case 23:
|
||||
case 123:
|
||||
case 124:
|
||||
case 29:
|
||||
case 33:
|
||||
case 151:
|
||||
case 178: {
|
||||
// TODO implement fully
|
||||
BlockState state = block.getState();
|
||||
if (state != null) {
|
||||
StateWrapper wrapper = new StateWrapper(state);
|
||||
CompoundTag rawTag = wrapper.getTag();
|
||||
if (rawTag != null) {
|
||||
Map<String, Tag> values = new HashMap<String, Tag>();
|
||||
for (Entry<String, Tag> entry : rawTag.getValue().entrySet()) {
|
||||
values.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
values.put("id", new StringTag("id", wrapper.getId()));
|
||||
values.put("x", new IntTag("x", x));
|
||||
values.put("y", new IntTag("y", y));
|
||||
values.put("z", new IntTag("z", z));
|
||||
CompoundTag tileEntityTag = new CompoundTag(values);
|
||||
tileEntities.add(tileEntityTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
default: {
|
||||
blockData[index] = block.getData();
|
||||
}
|
||||
}
|
||||
if (id > 255) {
|
||||
if (addBlocks == null) {
|
||||
addBlocks = new byte[(blocks.length >> 1) + 1];
|
||||
}
|
||||
addBlocks[index >> 1] = (byte) (((index & 1) == 0) ? (addBlocks[index >> 1] & 0xF0) | ((id >> 8) & 0xF) : (addBlocks[index >> 1] & 0xF) | (((id >> 8) & 0xF) << 4));
|
||||
}
|
||||
blocks[index] = (byte) id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
schematic.put("Blocks", new ByteArrayTag("Blocks", blocks));
|
||||
schematic.put("Data", new ByteArrayTag("Data", blockData));
|
||||
schematic.put("Entities", new ListTag("Entities", CompoundTag.class, new ArrayList<Tag>()));
|
||||
schematic.put("TileEntities", new ListTag("TileEntities", CompoundTag.class, tileEntities));
|
||||
|
||||
if (addBlocks != null) {
|
||||
schematic.put("AddBlocks", new ByteArrayTag("AddBlocks", addBlocks));
|
||||
}
|
||||
return new CompoundTag("Schematic", schematic);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,57 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotBlock;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.intellectualcrafters.plot.object.PlotLoc;
|
||||
import com.intellectualcrafters.plot.object.RegionWrapper;
|
||||
import com.intellectualcrafters.plot.util.SetBlockQueue.ChunkWrapper;
|
||||
|
||||
public abstract class ChunkManager {
|
||||
|
||||
public static ChunkManager manager = null;
|
||||
public static RegionWrapper CURRENT_PLOT_CLEAR = null;
|
||||
public static boolean FORCE_PASTE = false;
|
||||
|
||||
public static HashMap<PlotLoc, HashMap<Short, Short>> GENERATE_BLOCKS = new HashMap<>();
|
||||
public static HashMap<PlotLoc, HashMap<Short, Byte>> GENERATE_DATA = new HashMap<>();
|
||||
|
||||
public static ChunkLoc getChunkChunk(final Location loc) {
|
||||
final int x = loc.getX() >> 9;
|
||||
final int z = loc.getZ() >> 9;
|
||||
return new ChunkLoc(x, z);
|
||||
}
|
||||
|
||||
public abstract void setChunk(ChunkWrapper loc, PlotBlock[][] result);
|
||||
|
||||
public abstract int[] countEntities(Plot plot);
|
||||
|
||||
public abstract boolean loadChunk(String world, ChunkLoc loc);
|
||||
|
||||
public abstract boolean unloadChunk(String world, ChunkLoc loc);
|
||||
|
||||
public abstract List<ChunkLoc> getChunkChunks(String world);
|
||||
|
||||
public abstract void regenerateChunk(String world, ChunkLoc loc);
|
||||
|
||||
public abstract void deleteRegionFile(final String world, final ChunkLoc loc);
|
||||
|
||||
public abstract void deleteRegionFiles(final String world, final List<ChunkLoc> chunks);
|
||||
|
||||
public abstract Plot hasPlot(String world, ChunkLoc chunk);
|
||||
|
||||
public abstract boolean copyRegion(final Location pos1, final Location pos2, final Location newPos, final Runnable whenDone);
|
||||
|
||||
public abstract boolean regenerateRegion(final Location pos1, final Location pos2, final Runnable whenDone);
|
||||
|
||||
public abstract void clearAllEntities(final Plot plot);
|
||||
|
||||
public abstract void swap(String world, PlotId id, PlotId plotid);
|
||||
|
||||
public abstract void swap(String worldname, Location bot1, Location top1, Location bot2, Location top2);
|
||||
}
|
@ -0,0 +1,290 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Random;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.generator.AugmentedPopulator;
|
||||
import com.intellectualcrafters.plot.object.BlockLoc;
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotCluster;
|
||||
import com.intellectualcrafters.plot.object.PlotClusterId;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.intellectualcrafters.plot.object.PlotManager;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.PlotWorld;
|
||||
import com.intellectualcrafters.plot.util.bukkit.BukkitUtil;
|
||||
import com.intellectualcrafters.plot.util.bukkit.UUIDHandler;
|
||||
|
||||
public class ClusterManager {
|
||||
public static HashMap<String, HashSet<PlotCluster>> clusters;
|
||||
public static PlotCluster last;
|
||||
private static HashSet<String> regenerating = new HashSet<>();
|
||||
|
||||
public static boolean contains(final PlotCluster cluster, final PlotId id) {
|
||||
return (cluster.getP1().x <= id.x) && (cluster.getP1().y <= id.y) && (cluster.getP2().x >= id.x) && (cluster.getP2().y >= id.y);
|
||||
}
|
||||
|
||||
public static HashSet<PlotCluster> getClusters(final World world) {
|
||||
return getClusters(world.getName());
|
||||
}
|
||||
|
||||
public static HashSet<PlotCluster> getClusters(final String world) {
|
||||
if (clusters.containsKey(world)) {
|
||||
return clusters.get(world);
|
||||
}
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
public static Location getHome(final PlotCluster cluster) {
|
||||
final BlockLoc home = cluster.settings.getPosition();
|
||||
Location toReturn;
|
||||
if (home.y == 0) {
|
||||
// default pos
|
||||
final PlotId center = getCenterPlot(cluster);
|
||||
toReturn = MainUtil.getPlotHome(cluster.world, center);
|
||||
if (toReturn.getY() == 0) {
|
||||
final PlotManager manager = PS.get().getPlotManager(cluster.world);
|
||||
final PlotWorld plotworld = PS.get().getPlotWorld(cluster.world);
|
||||
final Location loc = manager.getSignLoc(plotworld, MainUtil.getPlot(cluster.world, center));
|
||||
toReturn.setY(loc.getY());
|
||||
}
|
||||
} else {
|
||||
toReturn = getClusterBottom(cluster).add(home.x, home.y, home.z);
|
||||
}
|
||||
final int max = BukkitUtil.getHeighestBlock(cluster.world, toReturn.getX(), toReturn.getZ());
|
||||
if (max > toReturn.getY()) {
|
||||
toReturn.setY(max);
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
public static PlotId getCenterPlot(final PlotCluster cluster) {
|
||||
final PlotId bot = cluster.getP1();
|
||||
final PlotId top = cluster.getP2();
|
||||
return new PlotId((bot.x + top.x) / 2, (bot.y + top.y) / 2);
|
||||
}
|
||||
|
||||
public static Location getClusterBottom(final PlotCluster cluster) {
|
||||
final String world = cluster.world;
|
||||
final PlotWorld plotworld = PS.get().getPlotWorld(world);
|
||||
final PlotManager manager = PS.get().getPlotManager(world);
|
||||
return manager.getPlotBottomLocAbs(plotworld, cluster.getP1());
|
||||
}
|
||||
|
||||
public static Location getClusterTop(final PlotCluster cluster) {
|
||||
final String world = cluster.world;
|
||||
final PlotWorld plotworld = PS.get().getPlotWorld(world);
|
||||
final PlotManager manager = PS.get().getPlotManager(world);
|
||||
return manager.getPlotTopLocAbs(plotworld, cluster.getP2());
|
||||
}
|
||||
|
||||
public static PlotCluster getCluster(final String world, final String name) {
|
||||
if (!clusters.containsKey(world)) {
|
||||
return null;
|
||||
}
|
||||
for (final PlotCluster cluster : clusters.get(world)) {
|
||||
if (cluster.getName().equals(name)) {
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean contains(final PlotCluster cluster, final Location loc) {
|
||||
final String world = loc.getWorld();
|
||||
final PlotManager manager = PS.get().getPlotManager(world);
|
||||
final PlotWorld plotworld = PS.get().getPlotWorld(world);
|
||||
final Location bot = manager.getPlotBottomLocAbs(plotworld, cluster.getP1());
|
||||
final Location top = manager.getPlotTopLocAbs(plotworld, cluster.getP2()).add(1, 0, 1);
|
||||
return (bot.getX() < loc.getX()) && (bot.getZ() < loc.getZ()) && (top.getX() > loc.getX()) && (top.getZ() > loc.getZ());
|
||||
}
|
||||
|
||||
public static HashSet<PlotCluster> getIntersects(final String world, final PlotClusterId id) {
|
||||
if (!clusters.containsKey(world)) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
final HashSet<PlotCluster> list = new HashSet<PlotCluster>();
|
||||
for (final PlotCluster cluster : clusters.get(world)) {
|
||||
if (intersects(cluster, id)) {
|
||||
list.add(cluster);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public static boolean intersects(final PlotCluster cluster, final PlotClusterId id) {
|
||||
final PlotId pos1 = cluster.getP1();
|
||||
final PlotId pos2 = cluster.getP2();
|
||||
return (pos1.x <= id.pos2.x) && (pos2.x >= id.pos1.x) && (pos1.y <= id.pos2.y) && (pos2.y >= id.pos1.y);
|
||||
}
|
||||
|
||||
public static PlotCluster getCluster(final Plot plot) {
|
||||
return getCluster(plot.world, plot.id);
|
||||
}
|
||||
|
||||
public static PlotCluster getClusterAbs(final Location loc) {
|
||||
String world = loc.getWorld();
|
||||
if ((last != null) && last.world.equals(world)) {
|
||||
if (contains(last, loc)) {
|
||||
return last;
|
||||
}
|
||||
}
|
||||
if (clusters == null) {
|
||||
return null;
|
||||
}
|
||||
final HashSet<PlotCluster> local = clusters.get(world);
|
||||
if (local == null) {
|
||||
return null;
|
||||
}
|
||||
for (final PlotCluster cluster : local) {
|
||||
if (contains(cluster, loc)) {
|
||||
last = cluster;
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PlotCluster getCluster(final Location loc) {
|
||||
final String world = loc.getWorld();
|
||||
PlotManager manager = PS.get().getPlotManager(world);
|
||||
PlotId id = manager.getPlotIdAbs(PS.get().getPlotWorld(world), loc.getX(), loc.getY(), loc.getZ());
|
||||
if (id != null) {
|
||||
return getCluster(world, id);
|
||||
}
|
||||
return getClusterAbs(loc);
|
||||
}
|
||||
|
||||
public static PlotCluster getCluster(final String world, final PlotId id) {
|
||||
if ((last != null) && last.world.equals(world)) {
|
||||
if (contains(last, id)) {
|
||||
return last;
|
||||
}
|
||||
}
|
||||
if (clusters == null) {
|
||||
return null;
|
||||
}
|
||||
final HashSet<PlotCluster> local = clusters.get(world);
|
||||
if (local == null) {
|
||||
return null;
|
||||
}
|
||||
for (final PlotCluster cluster : local) {
|
||||
if (contains(cluster, id)) {
|
||||
last = cluster;
|
||||
return cluster;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean removeCluster(final PlotCluster cluster) {
|
||||
if (clusters != null) {
|
||||
if (clusters.containsKey(cluster.world)) {
|
||||
clusters.get(cluster.world).remove(cluster);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static PlotClusterId getClusterId(final PlotCluster cluster) {
|
||||
return new PlotClusterId(cluster.getP1(), cluster.getP2());
|
||||
}
|
||||
|
||||
public static AugmentedPopulator getPopulator(final PlotCluster cluster) {
|
||||
final World world = Bukkit.getWorld(cluster.world);
|
||||
for (final BlockPopulator populator : world.getPopulators()) {
|
||||
if (populator instanceof AugmentedPopulator) {
|
||||
if (((AugmentedPopulator) populator).cluster.equals(cluster)) {
|
||||
return (AugmentedPopulator) populator;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PlotId estimatePlotId(final Location loc) {
|
||||
final PlotId a = new PlotId(0, 0);
|
||||
final PlotId b = new PlotId(1, 1);
|
||||
int xw;
|
||||
int zw;
|
||||
final String world = loc.getWorld();
|
||||
final PlotWorld plotworld = PS.get().getPlotWorld(world);
|
||||
if (plotworld == null) {
|
||||
xw = 39;
|
||||
zw = 39;
|
||||
} else {
|
||||
final PlotManager manager = PS.get().getPlotManager(world);
|
||||
final Location al = manager.getPlotBottomLocAbs(plotworld, a);
|
||||
final Location bl = manager.getPlotBottomLocAbs(plotworld, b);
|
||||
xw = bl.getX() - al.getX();
|
||||
zw = bl.getZ() - al.getZ();
|
||||
}
|
||||
final int x = loc.getX();
|
||||
final int z = loc.getZ();
|
||||
return new PlotId((x / xw) + 1, (z / zw) + 1);
|
||||
}
|
||||
|
||||
public static void regenCluster(final PlotCluster cluster) {
|
||||
if (regenerating.contains(cluster.world + ":" + cluster.getName())) {
|
||||
return;
|
||||
}
|
||||
regenerating.add(cluster.world + ":" + cluster.getName());
|
||||
final int interval = 1;
|
||||
int i = 0;
|
||||
final Random rand = new Random();
|
||||
final World world = Bukkit.getWorld(cluster.world);
|
||||
final PlotWorld plotworld = PS.get().getPlotWorld(cluster.world);
|
||||
final Location bot = getClusterBottom(cluster);
|
||||
final Location top = getClusterTop(cluster);
|
||||
final int minChunkX = bot.getX() >> 4;
|
||||
final int maxChunkX = (top.getX() >> 4) + 1;
|
||||
final int minChunkZ = bot.getZ() >> 4;
|
||||
final int maxChunkZ = (top.getZ() >> 4) + 1;
|
||||
final AugmentedPopulator populator = getPopulator(cluster);
|
||||
final ArrayList<Chunk> chunks = new ArrayList<>();
|
||||
TaskManager.runTaskLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
ClusterManager.regenerating.remove(cluster.world + ":" + cluster.getName());
|
||||
final PlotPlayer owner = UUIDHandler.getPlayer(cluster.owner);
|
||||
if (owner != null) {
|
||||
MainUtil.sendMessage(owner, C.CLEARING_DONE);
|
||||
}
|
||||
}
|
||||
}, (interval * chunks.size()) + 20);
|
||||
// chunks
|
||||
for (int x = minChunkX; x <= maxChunkX; x++) {
|
||||
for (int z = minChunkZ; z <= maxChunkZ; z++) {
|
||||
final Chunk chunk = world.getChunkAt(x, z);
|
||||
chunks.add(chunk);
|
||||
}
|
||||
}
|
||||
for (final Chunk chunk : chunks) {
|
||||
i += interval;
|
||||
TaskManager.runTaskLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if ((populator == null) || (plotworld.TYPE == 0)) {
|
||||
ChunkLoc loc = new ChunkLoc(chunk.getX(), chunk.getZ());
|
||||
ChunkManager.manager.regenerateChunk(world.getName(), loc);
|
||||
MainUtil.update(world.getName(), loc);
|
||||
} else {
|
||||
populator.populate(world, rand, chunk);
|
||||
}
|
||||
}
|
||||
}, i);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.object.CmdInstance;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
|
||||
public class CmdConfirm {
|
||||
private static HashMap<String, CmdInstance> pending = new HashMap<>();
|
||||
|
||||
public static CmdInstance getPending(PlotPlayer player) {
|
||||
if (player == null) {
|
||||
return pending.get("__CONSOLE__");
|
||||
}
|
||||
return pending.get(player.getName());
|
||||
}
|
||||
|
||||
public static void removePending(PlotPlayer player) {
|
||||
if (player == null) {
|
||||
pending.remove("__CONSOLE__");
|
||||
}
|
||||
else {
|
||||
pending.remove(player.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public static void removePending(String name) {
|
||||
pending.remove(name);
|
||||
}
|
||||
|
||||
public static void addPending(PlotPlayer player, String commandStr, Runnable runnable) {
|
||||
MainUtil.sendMessage(player, C.REQUIRES_CONFIRM, commandStr);
|
||||
CmdInstance cmd = new CmdInstance(runnable);
|
||||
String name;
|
||||
if (player == null) {
|
||||
name = "__CONSOLE__";
|
||||
}
|
||||
else {
|
||||
name = player.getName();
|
||||
}
|
||||
pending.put(name, cmd);
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
public class ConsoleColors {
|
||||
public static String fromString(String input) {
|
||||
input = input.replaceAll("&0", fromChatColor("&0")).replaceAll("&1", fromChatColor("&1")).replaceAll("&2", fromChatColor("&2")).replaceAll("&3", fromChatColor("&3")).replaceAll("&4", fromChatColor("&4")).replaceAll("&5", fromChatColor("&5")).replaceAll("&6", fromChatColor("&6")).replaceAll("&7", fromChatColor("&7")).replaceAll("&8", fromChatColor("&8")).replaceAll("&9", fromChatColor("&9")).replaceAll("&a", fromChatColor("&a")).replaceAll("&b", fromChatColor("&b")).replaceAll("&c", fromChatColor("&c")).replaceAll("&d", fromChatColor("&d")).replaceAll("&e", fromChatColor("&e")).replaceAll("&f", fromChatColor("&f")).replaceAll("&k", fromChatColor("&k")).replaceAll("&l", fromChatColor("&l")).replaceAll("&m", fromChatColor("&m"))
|
||||
.replaceAll("&n", fromChatColor("&n")).replaceAll("&o", fromChatColor("&o")).replaceAll("&r", fromChatColor("&r"));
|
||||
return input + "\u001B[0m";
|
||||
}
|
||||
|
||||
/*
|
||||
* public static final String ANSI_RESET = "\u001B[0m"; public static final
|
||||
* String ANSI_BLACK = "\u001B[30m"; public static final String ANSI_RED =
|
||||
* "\u001B[31m"; public static final String ANSI_GREEN = "\u001B[32m";
|
||||
* public static final String ANSI_YELLOW = "\u001B[33m"; public static
|
||||
* final String ANSI_BLUE = "\u001B[34m"; public static final String
|
||||
* ANSI_PURPLE = "\u001B[35m"; public static final String ANSI_CYAN =
|
||||
* "\u001B[36m"; public static final String ANSI_WHITE = "\u001B[37m";
|
||||
* public static final String ANSI_BOLD = "\033[1m"; public static final
|
||||
* String ANSI_UNDERLINE = "\033[0m"; public static final String ANSI_ITALIC
|
||||
* = "\033[3m]";
|
||||
*/
|
||||
public static String fromChatColor(final String color) {
|
||||
return chatColor(color).getLin();
|
||||
}
|
||||
|
||||
public static ConsoleColor chatColor(final String color) {
|
||||
switch (color) {
|
||||
case "&r":
|
||||
return ConsoleColor.RESET;
|
||||
case "&7":
|
||||
case "&8":
|
||||
return ConsoleColor.WHITE;
|
||||
case "&0":
|
||||
return ConsoleColor.BLACK;
|
||||
case "&4":
|
||||
case "&c":
|
||||
return ConsoleColor.RED;
|
||||
case "&6":
|
||||
case "&e":
|
||||
return ConsoleColor.YELLOW;
|
||||
case "&a":
|
||||
case "&2":
|
||||
return ConsoleColor.GREEN;
|
||||
case "&b":
|
||||
case "&3":
|
||||
return ConsoleColor.CYAN;
|
||||
case "&d":
|
||||
case "&5":
|
||||
return ConsoleColor.PURPLE;
|
||||
case "&9":
|
||||
case "&1":
|
||||
return ConsoleColor.BLUE;
|
||||
case "&n":
|
||||
return ConsoleColor.UNDERLINE;
|
||||
case "&o":
|
||||
return ConsoleColor.ITALIC;
|
||||
case "&l":
|
||||
return ConsoleColor.BOLD;
|
||||
default:
|
||||
return ConsoleColor.RESET;
|
||||
}
|
||||
}
|
||||
|
||||
static enum ConsoleColor {
|
||||
RESET("\u001B[0m"),
|
||||
BLACK("\u001B[30m"),
|
||||
RED("\u001B[31m"),
|
||||
GREEN("\u001B[32m"),
|
||||
YELLOW("\u001B[33m"),
|
||||
BLUE("\u001B[34m"),
|
||||
PURPLE("\u001B[35m"),
|
||||
CYAN("\u001B[36m"),
|
||||
WHITE("\u001B[37m"),
|
||||
BOLD("\033[1m"),
|
||||
UNDERLINE("\033[0m"),
|
||||
ITALIC("\033[3m");
|
||||
private final String win;
|
||||
private final String lin;
|
||||
|
||||
ConsoleColor(final String lin) {
|
||||
this.lin = lin;
|
||||
this.win = lin;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String getWin() {
|
||||
return this.win;
|
||||
}
|
||||
|
||||
public String getLin() {
|
||||
return this.lin;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
|
||||
public abstract class EconHandler {
|
||||
public static EconHandler manager;
|
||||
|
||||
public abstract double getMoney(PlotPlayer player);
|
||||
public abstract void withdrawMoney(PlotPlayer player, double amount);
|
||||
public abstract void depositMoney(PlotPlayer player, double amount);
|
||||
public abstract void depositMoney(OfflinePlotPlayer player, double amount);
|
||||
public abstract void setPermission(PlotPlayer player, String perm, boolean value);
|
||||
}
|
300
src/main/java/com/intellectualcrafters/plot/util/EventUtil.java
Normal file
300
src/main/java/com/intellectualcrafters/plot/util/EventUtil.java
Normal file
@ -0,0 +1,300 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.flag.Flag;
|
||||
import com.intellectualcrafters.plot.flag.FlagManager;
|
||||
import com.intellectualcrafters.plot.flag.FlagValue.PlotBlockListValue;
|
||||
import com.intellectualcrafters.plot.listeners.PlayerBlockEventType;
|
||||
import com.intellectualcrafters.plot.object.LazyBlock;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotBlock;
|
||||
import com.intellectualcrafters.plot.object.PlotCluster;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
|
||||
public abstract class EventUtil {
|
||||
|
||||
public static EventUtil manager = null;
|
||||
|
||||
public static void unregisterPlayer(PlotPlayer player) {
|
||||
String name = player.getName();
|
||||
if (SetupUtils.setupMap.containsKey(name)) {
|
||||
SetupUtils.setupMap.remove(name);
|
||||
}
|
||||
CmdConfirm.removePending(name);
|
||||
PS.get().IMP.unregister(player);
|
||||
}
|
||||
|
||||
public abstract boolean callClaim(final PlotPlayer player, final Plot plot, final boolean auto);
|
||||
|
||||
public abstract boolean callTeleport(final PlotPlayer player, Location from, final Plot plot);
|
||||
|
||||
public abstract boolean callClear(final String world, final PlotId id);
|
||||
|
||||
public abstract void callDelete(final String world, final PlotId id);
|
||||
|
||||
public abstract boolean callFlagAdd(final Flag flag, final Plot plot);
|
||||
|
||||
public abstract boolean callFlagRemove(final Flag flag, final Plot plot);
|
||||
|
||||
public abstract boolean callFlagRemove(final Flag flag, final PlotCluster cluster);
|
||||
|
||||
public abstract boolean callMerge(final String world, final Plot plot, final ArrayList<PlotId> plots);
|
||||
|
||||
public abstract boolean callUnlink(final String world, final ArrayList<PlotId> plots);
|
||||
|
||||
public abstract void callEntry(final PlotPlayer player, final Plot plot);
|
||||
|
||||
public abstract void callLeave(final PlotPlayer player, final Plot plot);
|
||||
|
||||
public abstract void callDenied(final PlotPlayer initiator, final Plot plot, final UUID player, final boolean added);
|
||||
|
||||
public abstract void callTrusted(final PlotPlayer initiator, final Plot plot, final UUID player, final boolean added);
|
||||
|
||||
public abstract void callMember(final PlotPlayer initiator, final Plot plot, final UUID player, final boolean added);
|
||||
|
||||
public boolean checkPlayerBlockEvent(PlotPlayer pp, PlayerBlockEventType type, Location loc, LazyBlock block, boolean notifyPerms) {
|
||||
Plot plot = MainUtil.getPlot(loc);
|
||||
UUID uuid = pp.getUUID();
|
||||
if (plot == null) {
|
||||
if (!MainUtil.isPlotAreaAbs(loc)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (plot.isAdded(uuid)) {
|
||||
return true;
|
||||
}
|
||||
switch (type) {
|
||||
case TELEPORT_OBJECT: {
|
||||
return false;
|
||||
}
|
||||
case EAT:
|
||||
case READ: {
|
||||
return true;
|
||||
}
|
||||
case BREAK_BLOCK: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "break");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case BREAK_HANGING:
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (FlagManager.isPlotFlagTrue(plot, "hanging-break")) {
|
||||
return true;
|
||||
}
|
||||
if (plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_OTHER.s, notifyPerms);
|
||||
}
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_UNOWNED.s, notifyPerms);
|
||||
case BREAK_MISC:
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (FlagManager.isPlotFlagTrue(plot, "misc-break")) {
|
||||
return true;
|
||||
}
|
||||
if (plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_OTHER.s, notifyPerms);
|
||||
}
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_UNOWNED.s, notifyPerms);
|
||||
case BREAK_VEHICLE:
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (FlagManager.isPlotFlagTrue(plot, "vehicle-break")) {
|
||||
return true;
|
||||
}
|
||||
if (plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_OTHER.s, notifyPerms);
|
||||
}
|
||||
return Permissions.hasPermission(pp, Permissions.BREAK_UNOWNED.s, notifyPerms);
|
||||
case INTERACT_BLOCK: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "use");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case PLACE_BLOCK: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.BUILD_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.BUILD_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "place");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.BUILD_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case TRIGGER_PHYSICAL: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_ROAD.s, false);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, false);
|
||||
}
|
||||
if (FlagManager.isPlotFlagTrue(plot, "device-interact")) {
|
||||
return true;
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "use");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case INTERACT_HANGING: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
if (FlagManager.isPlotFlagTrue(plot, "hanging-interact")) {
|
||||
return true;
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "use");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case INTERACT_MISC: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
if (FlagManager.isPlotFlagTrue(plot, "misc-interact")) {
|
||||
return true;
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "use");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case INTERACT_VEHICLE: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_ROAD.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
if (FlagManager.isPlotFlagTrue(plot, "vehicle-use")) {
|
||||
return true;
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "use");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case SPAWN_MOB: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
|
||||
if (FlagManager.isPlotFlagTrue(plot, "mob-place")) {
|
||||
return true;
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "place");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case PLACE_HANGING: {
|
||||
// if (plot == null) {
|
||||
// return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
// }
|
||||
// if (!plot.hasOwner()) {
|
||||
// return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, notifyPerms);
|
||||
// }
|
||||
//
|
||||
// if (FlagManager.isPlotFlagTrue(plot, "hanging-place")) {
|
||||
// return true;
|
||||
// }
|
||||
// Flag flag = FlagManager.getPlotFlag(plot, "place");
|
||||
// HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
// if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
// return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
// }
|
||||
return true;
|
||||
}
|
||||
case PLACE_MISC: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
|
||||
if (FlagManager.isPlotFlagTrue(plot, "misc-place")) {
|
||||
return true;
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "place");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
case PLACE_VEHICLE: {
|
||||
if (plot == null) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
if (!plot.hasOwner()) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_UNOWNED.s, notifyPerms);
|
||||
}
|
||||
|
||||
if (FlagManager.isPlotFlagTrue(plot, "vehicle-place")) {
|
||||
return true;
|
||||
}
|
||||
Flag flag = FlagManager.getPlotFlag(plot, "place");
|
||||
HashSet<PlotBlock> value = flag == null ? null : (HashSet<PlotBlock>) flag.getValue();
|
||||
if (value == null || (!value.contains(PlotBlock.EVERYTHING) && !value.contains(block.getPlotBlock()))) {
|
||||
return Permissions.hasPermission(pp, Permissions.INTERACT_OTHER.s, notifyPerms);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,286 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.config.Settings;
|
||||
import com.intellectualcrafters.plot.flag.Flag;
|
||||
import com.intellectualcrafters.plot.flag.FlagManager;
|
||||
import com.intellectualcrafters.plot.generator.ClassicPlotManager;
|
||||
import com.intellectualcrafters.plot.generator.HybridUtils;
|
||||
import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotHandler;
|
||||
import com.intellectualcrafters.plot.object.PlotManager;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.PlotWorld;
|
||||
import com.intellectualcrafters.plot.object.RunnableVal;
|
||||
import com.intellectualcrafters.plot.util.bukkit.UUIDHandler;
|
||||
|
||||
public class ExpireManager {
|
||||
public static ConcurrentHashMap<String, List<Plot>> expiredPlots = new ConcurrentHashMap<>();
|
||||
public static ConcurrentHashMap<String, Boolean> updatingPlots = new ConcurrentHashMap<>();
|
||||
public static ConcurrentHashMap<String, Long> timestamp = new ConcurrentHashMap<>();
|
||||
public static ConcurrentHashMap<UUID, Long> dates = new ConcurrentHashMap<>();
|
||||
public static int task;
|
||||
|
||||
public static long getTimeStamp(final String world) {
|
||||
if (timestamp.containsKey(world)) {
|
||||
return timestamp.get(world);
|
||||
} else {
|
||||
timestamp.put(world, 0l);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean updateExpired(final String world) {
|
||||
updatingPlots.put(world, true);
|
||||
final long now = System.currentTimeMillis();
|
||||
if (now > getTimeStamp(world)) {
|
||||
timestamp.put(world, now + 86400000l);
|
||||
TaskManager.runTaskAsync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
final List<Plot> plots = getOldPlots(world);
|
||||
PS.log("&7[&5Expire&dManager&7] &3Found " + plots.size() + " expired plots for " + world + "!");
|
||||
expiredPlots.put(world, plots);
|
||||
updatingPlots.put(world, false);
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
return true;
|
||||
} else {
|
||||
updatingPlots.put(world, false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void runTask() {
|
||||
ExpireManager.task = TaskManager.runTaskRepeat(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
for (final String world : PS.get().getPlotWorldsString()) {
|
||||
if (!ExpireManager.updatingPlots.containsKey(world)) {
|
||||
ExpireManager.updatingPlots.put(world, false);
|
||||
}
|
||||
final Boolean updating = ExpireManager.updatingPlots.get(world);
|
||||
if (updating) {
|
||||
PS.log("&7[&5Expire&dManager&7] &3Waiting on fetch...");
|
||||
return;
|
||||
}
|
||||
if (!expiredPlots.containsKey(world)) {
|
||||
PS.log("&7[&5Expire&dManager&7] &3Updating expired plots for: " + world);
|
||||
updateExpired(world);
|
||||
return;
|
||||
}
|
||||
final List<Plot> plots = expiredPlots.get(world);
|
||||
if ((plots == null) || (plots.size() == 0)) {
|
||||
if (updateExpired(world)) {
|
||||
PS.log("&7[&5Expire&dManager&7] &3Re-evaluating expired plots for: " + world);
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
final Plot plot = plots.iterator().next();
|
||||
if (!isExpired(plot)) {
|
||||
expiredPlots.get(world).remove(plot);
|
||||
PS.log("&7[&5Expire&dManager&7] &bSkipping no longer expired: " + plot);
|
||||
return;
|
||||
}
|
||||
for (final UUID helper : plot.trusted) {
|
||||
final PlotPlayer player = UUIDHandler.getPlayer(helper);
|
||||
if (player != null) {
|
||||
MainUtil.sendMessage(player, C.PLOT_REMOVED_USER, plot.id.toString());
|
||||
}
|
||||
}
|
||||
for (final UUID helper : plot.members) {
|
||||
final PlotPlayer player = UUIDHandler.getPlayer(helper);
|
||||
if (player != null) {
|
||||
MainUtil.sendMessage(player, C.PLOT_REMOVED_USER, plot.id.toString());
|
||||
}
|
||||
}
|
||||
final PlotManager manager = PS.get().getPlotManager(world);
|
||||
if (manager == null) {
|
||||
PS.log("&7[&5Expire&dManager&7] &cThis is a friendly reminder to create or delete " + world +" as it is currently setup incorrectly");
|
||||
expiredPlots.get(world).remove(plot);
|
||||
return;
|
||||
}
|
||||
final PlotWorld plotworld = PS.get().getPlotWorld(world);
|
||||
RunnableVal run = new RunnableVal<Integer>() {
|
||||
@Override
|
||||
public void run() {
|
||||
int changed = this.value;
|
||||
if (Settings.MIN_BLOCKS_CHANGED_IGNORED > 0 || Settings.MIN_BLOCKS_CHANGED > 0 && manager instanceof ClassicPlotManager) {
|
||||
if (changed >= Settings.MIN_BLOCKS_CHANGED && Settings.MIN_BLOCKS_CHANGED > 0) {
|
||||
PS.log("&7[&5Expire&dManager&7] &bKeep flag added to: " + plot.id + (changed != -1 ? " (changed " + value + ")" : ""));
|
||||
FlagManager.addPlotFlag(plot, new Flag(FlagManager.getFlag("keep"), true));
|
||||
expiredPlots.get(world).remove(plot);
|
||||
return;
|
||||
}
|
||||
else if (changed >= Settings.MIN_BLOCKS_CHANGED_IGNORED && Settings.MIN_BLOCKS_CHANGED_IGNORED > 0) {
|
||||
PS.log("&7[&5Expire&dManager&7] &bIgnoring modified plot: " + plot.id + (changed != -1 ? " (changed " + value + ")" : ""));
|
||||
FlagManager.addPlotFlag(plot, new Flag(FlagManager.getFlag("modified-blocks"), value));
|
||||
expiredPlots.get(world).remove(plot);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (plot.settings.isMerged()) {
|
||||
MainUtil.unlinkPlot(plot);
|
||||
}
|
||||
plot.delete();
|
||||
expiredPlots.get(world).remove(plot);
|
||||
PS.log("&7[&5Expire&dManager&7] &cDeleted expired plot: " + plot.id + (changed != -1 ? " (changed " + value + ")" : ""));
|
||||
PS.log("&3 - World: " + plot.world);
|
||||
if (plot.hasOwner()) {
|
||||
PS.log("&3 - Owner: " + UUIDHandler.getName(plot.owner));
|
||||
} else {
|
||||
PS.log("&3 - Owner: Unowned");
|
||||
}
|
||||
}
|
||||
};
|
||||
if (Settings.MIN_BLOCKS_CHANGED_IGNORED > 0 || Settings.MIN_BLOCKS_CHANGED > 0 && manager instanceof ClassicPlotManager) {
|
||||
Flag flag = FlagManager.getPlotFlagAbs(plot, "modified-blocks");
|
||||
if (flag != null) {
|
||||
if ((Integer) flag.getValue() > Settings.MIN_BLOCKS_CHANGED_IGNORED) {
|
||||
PS.log("&7[&5Expire&dManager&7] &bSkipping modified: " + plot);
|
||||
expiredPlots.get(world).remove(plot);
|
||||
this.run();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
HybridUtils.manager.checkModified(plot, run);
|
||||
}
|
||||
}
|
||||
else {
|
||||
run.value = -1;
|
||||
run.run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, Settings.CLEAR_INTERVAL * 20);
|
||||
}
|
||||
|
||||
public static boolean isExpired(final UUID uuid) {
|
||||
if (UUIDHandler.getPlayer(uuid) != null) {
|
||||
return false;
|
||||
}
|
||||
final String name = UUIDHandler.getName(uuid);
|
||||
if (name != null) {
|
||||
long last;
|
||||
if (dates.contains(uuid)) {
|
||||
last = dates.get(uuid);
|
||||
}
|
||||
else {
|
||||
final OfflinePlayer op = Bukkit.getOfflinePlayer(name);
|
||||
if (op.hasPlayedBefore()) {
|
||||
last = op.getLastPlayed();
|
||||
dates.put(uuid, last);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (last == 0) {
|
||||
return false;
|
||||
}
|
||||
final long compared = System.currentTimeMillis() - last;
|
||||
if (compared >= (86400000l * Settings.AUTO_CLEAR_DAYS)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isExpired(Plot plot) {
|
||||
for (UUID owner : PlotHandler.getOwners(plot)) {
|
||||
if (!isExpired(owner)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static List<Plot> getOldPlots(final String world) {
|
||||
final ArrayList<Plot> plots = new ArrayList<>(PS.get().getPlots(world).values());
|
||||
final List<Plot> toRemove = new ArrayList<>();
|
||||
Iterator<Plot> iter = plots.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Plot plot = iter.next();
|
||||
final Flag keepFlag = FlagManager.getPlotFlag(plot, "keep");
|
||||
if (keepFlag != null && (Boolean) keepFlag.getValue()) {
|
||||
continue;
|
||||
}
|
||||
final UUID uuid = plot.owner;
|
||||
if (uuid == null) {
|
||||
toRemove.add(plot);
|
||||
continue;
|
||||
}
|
||||
final PlotPlayer player = UUIDHandler.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
continue;
|
||||
}
|
||||
if (isExpired(plot)) {
|
||||
if (Settings.AUTO_CLEAR_CHECK_DISK) {
|
||||
final String worldname = Bukkit.getWorlds().get(0).getName();
|
||||
String foldername;
|
||||
String filename = null;
|
||||
if (PS.get().IMP.checkVersion(1, 7, 5)) {
|
||||
foldername = "playerdata";
|
||||
try {
|
||||
final OfflinePlotPlayer op = UUIDHandler.uuidWrapper.getOfflinePlayer(uuid);
|
||||
filename = op.getUUID() + ".dat";
|
||||
} catch (final Throwable e) {
|
||||
filename = uuid.toString() + ".dat";
|
||||
}
|
||||
} else {
|
||||
foldername = "players";
|
||||
final String playername = UUIDHandler.getName(uuid);
|
||||
if (playername != null) {
|
||||
filename = playername + ".dat";
|
||||
}
|
||||
}
|
||||
if (filename != null) {
|
||||
final File playerFile = new File(worldname + File.separator + foldername + File.separator + filename);
|
||||
if (!playerFile.exists()) {
|
||||
PS.log("Could not find file: " + filename);
|
||||
} else {
|
||||
try {
|
||||
long last = playerFile.lastModified();
|
||||
long compared = System.currentTimeMillis() - last;
|
||||
if (compared < (86400000l * Settings.AUTO_CLEAR_DAYS)) {
|
||||
continue;
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
PS.log("Please disable disk checking in old plot auto clearing; Could not read file: " + filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
toRemove.add(plot);
|
||||
}
|
||||
}
|
||||
return toRemove;
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import com.intellectualcrafters.plot.object.PlotInventory;
|
||||
import com.intellectualcrafters.plot.object.PlotItemStack;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
|
||||
/**
|
||||
* This class is only used by internal functions, for most cases use the PlotInventory class
|
||||
*/
|
||||
public abstract class InventoryUtil {
|
||||
|
||||
/**
|
||||
* This class is only used by internal functions, for most cases use the PlotInventory class
|
||||
*/
|
||||
public static InventoryUtil manager = null;
|
||||
public abstract void open(PlotInventory inv);
|
||||
public abstract void close(PlotInventory inv);
|
||||
public abstract void setItem(PlotInventory plotInventory, int index, PlotItemStack item);
|
||||
public abstract PlotItemStack[] getItems(PlotPlayer player);
|
||||
public abstract boolean isOpen(PlotInventory plotInventory);
|
||||
}
|
136
src/main/java/com/intellectualcrafters/plot/util/LSetCube.java
Normal file
136
src/main/java/com/intellectualcrafters/plot/util/LSetCube.java
Normal file
@ -0,0 +1,136 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import org.bukkit.Location;
|
||||
|
||||
/**
|
||||
* Cube utilities
|
||||
*
|
||||
* @author Citymonstret
|
||||
*/
|
||||
@SuppressWarnings({ "javadoc", "unused" })
|
||||
public class LSetCube {
|
||||
/**
|
||||
* Base locations
|
||||
*/
|
||||
private Location l1, l2;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param l1
|
||||
* @param l2
|
||||
*/
|
||||
public LSetCube(final Location l1, final Location l2) {
|
||||
this.l1 = l1;
|
||||
this.l1 = l2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Secondary constructor
|
||||
*
|
||||
* @param l1
|
||||
* @param size
|
||||
*/
|
||||
public LSetCube(final Location l1, final int size) {
|
||||
this.l1 = l1;
|
||||
this.l2 = l1.clone().add(size, size, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute min. of the cube
|
||||
*
|
||||
* @return abs. min
|
||||
*/
|
||||
public Location minLoc() {
|
||||
final int x = Math.min(this.l1.getBlockX(), this.l2.getBlockX());
|
||||
final int y = Math.min(this.l1.getBlockY(), this.l2.getBlockY());
|
||||
final int z = Math.min(this.l1.getBlockZ(), this.l2.getBlockZ());
|
||||
return new Location(this.l1.getWorld(), x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute max. of the cube
|
||||
*
|
||||
* @return abs. max
|
||||
*/
|
||||
public Location maxLoc() {
|
||||
final int x = Math.max(this.l1.getBlockX(), this.l2.getBlockX());
|
||||
final int y = Math.max(this.l1.getBlockY(), this.l2.getBlockY());
|
||||
final int z = Math.max(this.l1.getBlockZ(), this.l2.getBlockZ());
|
||||
return new Location(this.l1.getWorld(), x, y, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a LCycler for the cube.
|
||||
*
|
||||
* @return new lcycler
|
||||
*/
|
||||
public LCycler getCycler() {
|
||||
return new LCycler(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Citymonstret
|
||||
*/
|
||||
protected class LCycler {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private final Location min;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private final Location max;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Location current;
|
||||
|
||||
/**
|
||||
* @param cube
|
||||
*/
|
||||
public LCycler(final LSetCube cube) {
|
||||
this.min = cube.minLoc();
|
||||
this.max = cube.maxLoc();
|
||||
this.current = this.min;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return ((this.current.getBlockX() + 1) <= this.max.getBlockX()) && ((this.current.getBlockY() + 1) <= this.max.getBlockY()) && ((this.current.getBlockZ() + 1) <= this.max.getBlockZ());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
public Location getNext() {
|
||||
if (!hasNext()) {
|
||||
return null;
|
||||
}
|
||||
this.current = this.current.add(1, 1, 1);
|
||||
return this.current;
|
||||
}
|
||||
}
|
||||
}
|
103
src/main/java/com/intellectualcrafters/plot/util/Lag.java
Normal file
103
src/main/java/com/intellectualcrafters/plot/util/Lag.java
Normal file
@ -0,0 +1,103 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
/**
|
||||
* TPS and Lag Checker.
|
||||
*
|
||||
* @author Citymonstret
|
||||
*/
|
||||
public class Lag implements Runnable {
|
||||
/**
|
||||
* Ticks
|
||||
*/
|
||||
public final static long[] T = new long[600];
|
||||
/**
|
||||
* Tick count
|
||||
*/
|
||||
public static int TC = 0;
|
||||
/**
|
||||
* something :_:
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public static long LT = 0L;
|
||||
|
||||
/**
|
||||
* Get the server TPS
|
||||
*
|
||||
* @return server tick per second
|
||||
*/
|
||||
public static double getTPS() {
|
||||
return Math.round(getTPS(100)) > 20.0D ? 20.0D : Math.round(getTPS(100));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the tick per second (measured in $ticks)
|
||||
*
|
||||
* @param ticks Ticks
|
||||
*
|
||||
* @return ticks per second
|
||||
*/
|
||||
public static double getTPS(final int ticks) {
|
||||
if (TC < ticks) {
|
||||
return 20.0D;
|
||||
}
|
||||
final int t = (TC - 1 - ticks) % T.length;
|
||||
final long e = System.currentTimeMillis() - T[t];
|
||||
return ticks / (e / 1000.0D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of ticks since
|
||||
*
|
||||
* @param tI Ticks <
|
||||
*
|
||||
* @return number of ticks since $tI
|
||||
*/
|
||||
public static long getElapsed(final int tI) {
|
||||
final long t = T[tI % T.length];
|
||||
return System.currentTimeMillis() - t;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get lag percentage
|
||||
*
|
||||
* @return lag percentage
|
||||
*/
|
||||
public static double getPercentage() {
|
||||
return Math.round((1.0D - (Lag.getTPS() / 20.0D)) * 100.0D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get TPS percentage (of 20)
|
||||
*
|
||||
* @return TPS percentage
|
||||
*/
|
||||
public static double getFullPercentage() {
|
||||
return getTPS() * 5.0D;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
T[TC % T.length] = System.currentTimeMillis();
|
||||
TC++;
|
||||
}
|
||||
}
|
89
src/main/java/com/intellectualcrafters/plot/util/Logger.java
Normal file
89
src/main/java/com/intellectualcrafters/plot/util/Logger.java
Normal file
@ -0,0 +1,89 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
|
||||
/**
|
||||
* Logging of errors and debug messages.
|
||||
*
|
||||
* @author Citymonstret
|
||||
*/
|
||||
public class Logger {
|
||||
private static ArrayList<String> entries;
|
||||
private static File log;
|
||||
|
||||
public static void setup(final File file) {
|
||||
log = file;
|
||||
entries = new ArrayList<>();
|
||||
try {
|
||||
final BufferedReader reader = new BufferedReader(new FileReader(file));
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
entries.add(line);
|
||||
}
|
||||
reader.close();
|
||||
} catch (final IOException e) {
|
||||
PS.log(C.PREFIX.s() + "File setup error Logger#setup");
|
||||
}
|
||||
}
|
||||
|
||||
public static void write() throws IOException {
|
||||
final FileWriter writer = new FileWriter(log);
|
||||
for (final String string : entries) {
|
||||
writer.write(string + System.lineSeparator());
|
||||
}
|
||||
writer.close();
|
||||
}
|
||||
|
||||
public static void add(final LogLevel level, final String string) {
|
||||
append("[" + level.toString() + "] " + string);
|
||||
}
|
||||
|
||||
private static void append(final String string) {
|
||||
entries.add("[" + new Date().toString() + "]" + string);
|
||||
}
|
||||
|
||||
public enum LogLevel {
|
||||
GENERAL("General"),
|
||||
WARNING("Warning"),
|
||||
DANGER("Danger");
|
||||
private final String name;
|
||||
|
||||
LogLevel(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
}
|
1636
src/main/java/com/intellectualcrafters/plot/util/MainUtil.java
Normal file
1636
src/main/java/com/intellectualcrafters/plot/util/MainUtil.java
Normal file
File diff suppressed because it is too large
Load Diff
1003
src/main/java/com/intellectualcrafters/plot/util/NbtFactory.java
Normal file
1003
src/main/java/com/intellectualcrafters/plot/util/NbtFactory.java
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,90 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
|
||||
public enum Permissions {
|
||||
// ADMIN
|
||||
ADMIN("plots.admin", "do-not-change"),
|
||||
// BUILD
|
||||
BUILD_OTHER("plots.admin.build.other", "build"),
|
||||
BUILD_ROAD("plots.admin.build.road", "build"),
|
||||
BUILD_UNOWNED("plots.admin.build.unowned", "build"),
|
||||
// INTERACT
|
||||
INTERACT_OTHER("plots.admin.interact.other", "interact"),
|
||||
INTERACT_ROAD("plots.admin.interact.road", "interact"),
|
||||
INTERACT_UNOWNED("plots.admin.interact.unowned", "interact"),
|
||||
// BREAK
|
||||
BREAK_OTHER("plots.admin.break.other", "break"),
|
||||
BREAK_ROAD("plots.admin.break.road", "break"),
|
||||
BREAK_UNOWNED("plots.admin.break.unowned", "break"),
|
||||
// MERGE
|
||||
MERGE_OTHER("plots.merge.other", "merge");
|
||||
|
||||
public String s;
|
||||
public String cat;
|
||||
|
||||
Permissions(String perm, String cat) {
|
||||
this.s = perm;
|
||||
this.cat = cat;
|
||||
}
|
||||
|
||||
public static boolean hasPermission(final PlotPlayer player, final Permissions perm) {
|
||||
return hasPermission(player, perm.s);
|
||||
}
|
||||
|
||||
|
||||
public static boolean hasPermission(final PlotPlayer player, final String perm) {
|
||||
if ((player == null) || player.isOp() || player.hasPermission(ADMIN.s)) {
|
||||
return true;
|
||||
}
|
||||
if (player.hasPermission(perm)) {
|
||||
return true;
|
||||
}
|
||||
final String[] nodes = perm.split("\\.");
|
||||
final StringBuilder n = new StringBuilder();
|
||||
for (int i = 0; i < (nodes.length - 1); i++) {
|
||||
n.append(nodes[i] + ("."));
|
||||
if (player.hasPermission(n + "*")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasPermission(final PlotPlayer player, final String perm, boolean notify) {
|
||||
if ((player == null) || player.isOp() || player.hasPermission(ADMIN.s)) {
|
||||
return true;
|
||||
}
|
||||
if (player.hasPermission(perm)) {
|
||||
return true;
|
||||
}
|
||||
final String[] nodes = perm.split("\\.");
|
||||
final StringBuilder n = new StringBuilder();
|
||||
for (int i = 0; i < (nodes.length - 1); i++) {
|
||||
n.append(nodes[i] + ("."));
|
||||
if (player.hasPermission(n + "*")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (notify) {
|
||||
MainUtil.sendMessage(player, C.NO_PERMISSION, perm);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int hasPermissionRange(final PlotPlayer player, final String stub, final int range) {
|
||||
if ((player == null) || player.isOp() || player.hasPermission(ADMIN.s)) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
if (player.hasPermission(stub + ".*")) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
for (int i = range; i > 0; i--) {
|
||||
if (player.hasPermission(stub + "." + i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
|
||||
public abstract class PlayerManager {
|
||||
public static PlayerManager manager;
|
||||
|
||||
public abstract void kickPlayer(PlotPlayer player, String reason);
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
|
||||
/**
|
||||
* Created 2014-09-29 for PlotSquared
|
||||
*
|
||||
* @author Citymonstret
|
||||
*/
|
||||
public class PlotSquaredException extends RuntimeException {
|
||||
public PlotSquaredException(final PlotError error, final String details) {
|
||||
super("PlotError >> " + error.getHeader() + ": " + details);
|
||||
PS.log("&cPlotError &6>> &c" + error.getHeader() + ": &6" + details);
|
||||
}
|
||||
|
||||
public static enum PlotError {
|
||||
PLOTMAIN_NULL("The PlotSquared instance was null"),
|
||||
MISSING_DEPENDENCY("Missing Dependency");
|
||||
private final String errorHeader;
|
||||
|
||||
PlotError(final String errorHeader) {
|
||||
this.errorHeader = errorHeader;
|
||||
}
|
||||
|
||||
public String getHeader() {
|
||||
return this.errorHeader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return this.getHeader();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
/**
|
||||
* Reflection Utilities for minecraft
|
||||
*
|
||||
*/
|
||||
public class ReflectionUtil {
|
||||
public static Class<?> getNmsClass(final String name) {
|
||||
final String className = "net.minecraft.server." + getVersion() + "." + name;
|
||||
return getClass(className);
|
||||
}
|
||||
|
||||
public static Class<?> getCbClass(final String name) {
|
||||
final String className = "org.bukkit.craftbukkit." + getVersion() + "." + name;
|
||||
return getClass(className);
|
||||
}
|
||||
|
||||
public static Class<?> getUtilClass(final String name) {
|
||||
try {
|
||||
return Class.forName(name); //Try before 1.8 first
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
try {
|
||||
return Class.forName("net.minecraft.util." + name); //Not 1.8
|
||||
} catch (final ClassNotFoundException ex2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
final String packageName = Bukkit.getServer().getClass().getPackage().getName();
|
||||
return packageName.substring(packageName.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
public static Object getHandle(final Object wrapper) {
|
||||
final Method getHandle = makeMethod(wrapper.getClass(), "getHandle");
|
||||
return callMethod(getHandle, wrapper);
|
||||
}
|
||||
|
||||
//Utils
|
||||
public static Method makeMethod(final Class<?> clazz, final String methodName, final Class<?>... paramaters) {
|
||||
try {
|
||||
return clazz.getDeclaredMethod(methodName, paramaters);
|
||||
} catch (final NoSuchMethodException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T callMethod(final Method method, final Object instance, final Object... paramaters) {
|
||||
if (method == null) {
|
||||
throw new RuntimeException("No such method");
|
||||
}
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
return (T) method.invoke(instance, paramaters);
|
||||
} catch (final InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex.getCause());
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Constructor<T> makeConstructor(final Class<?> clazz, final Class<?>... paramaterTypes) {
|
||||
try {
|
||||
return (Constructor<T>) clazz.getConstructor(paramaterTypes);
|
||||
} catch (final NoSuchMethodException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T callConstructor(final Constructor<T> constructor, final Object... paramaters) {
|
||||
if (constructor == null) {
|
||||
throw new RuntimeException("No such constructor");
|
||||
}
|
||||
constructor.setAccessible(true);
|
||||
try {
|
||||
return constructor.newInstance(paramaters);
|
||||
} catch (final InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex.getCause());
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Field makeField(final Class<?> clazz, final String name) {
|
||||
try {
|
||||
return clazz.getDeclaredField(name);
|
||||
} catch (final NoSuchFieldException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getField(final Field field, final Object instance) {
|
||||
if (field == null) {
|
||||
throw new RuntimeException("No such field");
|
||||
}
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
return (T) field.get(instance);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setField(final Field field, final Object instance, final Object value) {
|
||||
if (field == null) {
|
||||
throw new RuntimeException("No such field");
|
||||
}
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
field.set(instance, value);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getClass(final String name) {
|
||||
try {
|
||||
return Class.forName(name);
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Class<? extends T> getClass(final String name, final Class<T> superClass) {
|
||||
try {
|
||||
return Class.forName(name).asSubclass(superClass);
|
||||
} catch (ClassCastException | ClassNotFoundException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,728 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Server;
|
||||
|
||||
/**
|
||||
* @author DPOH-VAR
|
||||
* @version 1.0
|
||||
*/
|
||||
@SuppressWarnings({ "UnusedDeclaration", "rawtypes" })
|
||||
public class ReflectionUtils {
|
||||
/**
|
||||
* prefix of bukkit classes
|
||||
*/
|
||||
private static String preClassB = "org.bukkit.craftbukkit";
|
||||
/**
|
||||
* prefix of minecraft classes
|
||||
*/
|
||||
private static String preClassM = "net.minecraft.server";
|
||||
/**
|
||||
* boolean value, TRUE if server uses forge or MCPC+
|
||||
*/
|
||||
private static boolean forge = false;
|
||||
/** check server version and class names */
|
||||
static {
|
||||
if (Bukkit.getServer() != null) {
|
||||
if (Bukkit.getVersion().contains("MCPC") || Bukkit.getVersion().contains("Forge")) {
|
||||
forge = true;
|
||||
}
|
||||
final Server server = Bukkit.getServer();
|
||||
final Class<?> bukkitServerClass = server.getClass();
|
||||
String[] pas = bukkitServerClass.getName().split("\\.");
|
||||
if (pas.length == 5) {
|
||||
final String verB = pas[3];
|
||||
preClassB += "." + verB;
|
||||
}
|
||||
try {
|
||||
final Method getHandle = bukkitServerClass.getDeclaredMethod("getHandle");
|
||||
final Object handle = getHandle.invoke(server);
|
||||
final Class handleServerClass = handle.getClass();
|
||||
pas = handleServerClass.getName().split("\\.");
|
||||
if (pas.length == 5) {
|
||||
final String verM = pas[3];
|
||||
preClassM += "." + verM;
|
||||
}
|
||||
} catch (final Exception ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getNmsClass(final String name) {
|
||||
final String className = "net.minecraft.server." + getVersion() + "." + name;
|
||||
return getClass(className);
|
||||
}
|
||||
|
||||
public static Class<?> getCbClass(final String name) {
|
||||
final String className = "org.bukkit.craftbukkit." + getVersion() + "." + name;
|
||||
return getClass(className);
|
||||
}
|
||||
|
||||
public static Class<?> getUtilClass(final String name) {
|
||||
try {
|
||||
return Class.forName(name); //Try before 1.8 first
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
try {
|
||||
return Class.forName("net.minecraft.util." + name); //Not 1.8
|
||||
} catch (final ClassNotFoundException ex2) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
final String packageName = Bukkit.getServer().getClass().getPackage().getName();
|
||||
return packageName.substring(packageName.lastIndexOf('.') + 1);
|
||||
}
|
||||
|
||||
public static Object getHandle(final Object wrapper) {
|
||||
final Method getHandle = makeMethod(wrapper.getClass(), "getHandle");
|
||||
return callMethod(getHandle, wrapper);
|
||||
}
|
||||
|
||||
//Utils
|
||||
public static Method makeMethod(final Class<?> clazz, final String methodName, final Class<?>... paramaters) {
|
||||
try {
|
||||
return clazz.getDeclaredMethod(methodName, paramaters);
|
||||
} catch (final NoSuchMethodException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T callMethod(final Method method, final Object instance, final Object... paramaters) {
|
||||
if (method == null) {
|
||||
throw new RuntimeException("No such method");
|
||||
}
|
||||
method.setAccessible(true);
|
||||
try {
|
||||
return (T) method.invoke(instance, paramaters);
|
||||
} catch (final InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex.getCause());
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> Constructor<T> makeConstructor(final Class<?> clazz, final Class<?>... paramaterTypes) {
|
||||
try {
|
||||
return (Constructor<T>) clazz.getConstructor(paramaterTypes);
|
||||
} catch (final NoSuchMethodException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> T callConstructor(final Constructor<T> constructor, final Object... paramaters) {
|
||||
if (constructor == null) {
|
||||
throw new RuntimeException("No such constructor");
|
||||
}
|
||||
constructor.setAccessible(true);
|
||||
try {
|
||||
return constructor.newInstance(paramaters);
|
||||
} catch (final InvocationTargetException ex) {
|
||||
throw new RuntimeException(ex.getCause());
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Field makeField(final Class<?> clazz, final String name) {
|
||||
try {
|
||||
return clazz.getDeclaredField(name);
|
||||
} catch (final NoSuchFieldException ex) {
|
||||
return null;
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getField(final Field field, final Object instance) {
|
||||
if (field == null) {
|
||||
throw new RuntimeException("No such field");
|
||||
}
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
return (T) field.get(instance);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setField(final Field field, final Object instance, final Object value) {
|
||||
if (field == null) {
|
||||
throw new RuntimeException("No such field");
|
||||
}
|
||||
field.setAccessible(true);
|
||||
try {
|
||||
field.set(instance, value);
|
||||
} catch (final Exception ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static Class<?> getClass(final String name) {
|
||||
try {
|
||||
return Class.forName(name);
|
||||
} catch (final ClassNotFoundException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Class<? extends T> getClass(final String name, final Class<T> superClass) {
|
||||
try {
|
||||
return Class.forName(name).asSubclass(superClass);
|
||||
} catch (ClassCastException | ClassNotFoundException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if server has forge classes
|
||||
*/
|
||||
public static boolean isForge() {
|
||||
return forge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class for name. Replace {nms} to net.minecraft.server.V*. Replace {cb} to org.bukkit.craftbukkit.V*. Replace
|
||||
* {nm} to net.minecraft
|
||||
*
|
||||
* @param classes possible class paths
|
||||
*
|
||||
* @return RefClass object
|
||||
*
|
||||
* @throws RuntimeException if no class found
|
||||
*/
|
||||
public static RefClass getRefClass(final String... classes) throws RuntimeException {
|
||||
for (String className : classes) {
|
||||
try {
|
||||
className = className.replace("{cb}", preClassB).replace("{nms}", preClassM).replace("{nm}", "net.minecraft");
|
||||
return getRefClass(Class.forName(className));
|
||||
} catch (final ClassNotFoundException ignored) {
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no class found");
|
||||
}
|
||||
|
||||
/**
|
||||
* get RefClass object by real class
|
||||
*
|
||||
* @param clazz class
|
||||
*
|
||||
* @return RefClass based on passed class
|
||||
*/
|
||||
public static RefClass getRefClass(final Class clazz) {
|
||||
return new RefClass(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* RefClass - utility to simplify work with reflections.
|
||||
*/
|
||||
public static class RefClass {
|
||||
private final Class<?> clazz;
|
||||
|
||||
private RefClass(final Class<?> clazz) {
|
||||
this.clazz = clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* get passed class
|
||||
*
|
||||
* @return class
|
||||
*/
|
||||
public Class<?> getRealClass() {
|
||||
return this.clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* see {@link Class#isInstance(Object)}
|
||||
*
|
||||
* @param object the object to check
|
||||
*
|
||||
* @return true if object is an instance of this class
|
||||
*/
|
||||
public boolean isInstance(final Object object) {
|
||||
return this.clazz.isInstance(object);
|
||||
}
|
||||
|
||||
/**
|
||||
* get existing method by name and types
|
||||
*
|
||||
* @param name name
|
||||
* @param types method parameters. can be Class or RefClass
|
||||
*
|
||||
* @return RefMethod object
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod getMethod(final String name, final Object... types) throws NoSuchMethodException {
|
||||
try {
|
||||
final Class[] classes = new Class[types.length];
|
||||
int i = 0;
|
||||
for (final Object e : types) {
|
||||
if (e instanceof Class) {
|
||||
classes[i++] = (Class) e;
|
||||
} else if (e instanceof RefClass) {
|
||||
classes[i++] = ((RefClass) e).getRealClass();
|
||||
} else {
|
||||
classes[i++] = e.getClass();
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new RefMethod(this.clazz.getMethod(name, classes));
|
||||
} catch (final NoSuchMethodException ignored) {
|
||||
return new RefMethod(this.clazz.getDeclaredMethod(name, classes));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get existing constructor by types
|
||||
*
|
||||
* @param types parameters. can be Class or RefClass
|
||||
*
|
||||
* @return RefMethod object
|
||||
*
|
||||
* @throws RuntimeException if constructor not found
|
||||
*/
|
||||
public RefConstructor getConstructor(final Object... types) {
|
||||
try {
|
||||
final Class[] classes = new Class[types.length];
|
||||
int i = 0;
|
||||
for (final Object e : types) {
|
||||
if (e instanceof Class) {
|
||||
classes[i++] = (Class) e;
|
||||
} else if (e instanceof RefClass) {
|
||||
classes[i++] = ((RefClass) e).getRealClass();
|
||||
} else {
|
||||
classes[i++] = e.getClass();
|
||||
}
|
||||
}
|
||||
try {
|
||||
return new RefConstructor(this.clazz.getConstructor(classes));
|
||||
} catch (final NoSuchMethodException ignored) {
|
||||
return new RefConstructor(this.clazz.getDeclaredConstructor(classes));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find method by type parameters
|
||||
*
|
||||
* @param types parameters. can be Class or RefClass
|
||||
*
|
||||
* @return RefMethod object
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod findMethod(final Object... types) {
|
||||
final Class[] classes = new Class[types.length];
|
||||
int t = 0;
|
||||
for (final Object e : types) {
|
||||
if (e instanceof Class) {
|
||||
classes[t++] = (Class) e;
|
||||
} else if (e instanceof RefClass) {
|
||||
classes[t++] = ((RefClass) e).getRealClass();
|
||||
} else {
|
||||
classes[t++] = e.getClass();
|
||||
}
|
||||
}
|
||||
final List<Method> methods = new ArrayList<>();
|
||||
Collections.addAll(methods, this.clazz.getMethods());
|
||||
Collections.addAll(methods, this.clazz.getDeclaredMethods());
|
||||
findMethod: for (final Method m : methods) {
|
||||
final Class<?>[] methodTypes = m.getParameterTypes();
|
||||
if (methodTypes.length != classes.length) {
|
||||
continue;
|
||||
}
|
||||
for (final Class aClass : classes) {
|
||||
if (!Arrays.equals(classes, methodTypes)) {
|
||||
continue findMethod;
|
||||
}
|
||||
return new RefMethod(m);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such method");
|
||||
}
|
||||
|
||||
/**
|
||||
* find method by name
|
||||
*
|
||||
* @param names possible names of method
|
||||
*
|
||||
* @return RefMethod object
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod findMethodByName(final String... names) {
|
||||
final List<Method> methods = new ArrayList<>();
|
||||
Collections.addAll(methods, this.clazz.getMethods());
|
||||
Collections.addAll(methods, this.clazz.getDeclaredMethods());
|
||||
for (final Method m : methods) {
|
||||
for (final String name : names) {
|
||||
if (m.getName().equals(name)) {
|
||||
return new RefMethod(m);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such method");
|
||||
}
|
||||
|
||||
/**
|
||||
* find method by return value
|
||||
*
|
||||
* @param type type of returned value
|
||||
*
|
||||
* @return RefMethod
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod findMethodByReturnType(final RefClass type) {
|
||||
return findMethodByReturnType(type.clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* find method by return value
|
||||
*
|
||||
* @param type type of returned value
|
||||
*
|
||||
* @return RefMethod
|
||||
*
|
||||
* @throws RuntimeException if method not found
|
||||
*/
|
||||
public RefMethod findMethodByReturnType(Class type) {
|
||||
if (type == null) {
|
||||
type = void.class;
|
||||
}
|
||||
final List<Method> methods = new ArrayList<>();
|
||||
Collections.addAll(methods, this.clazz.getMethods());
|
||||
Collections.addAll(methods, this.clazz.getDeclaredMethods());
|
||||
for (final Method m : methods) {
|
||||
if (type.equals(m.getReturnType())) {
|
||||
return new RefMethod(m);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such method");
|
||||
}
|
||||
|
||||
/**
|
||||
* find constructor by number of arguments
|
||||
*
|
||||
* @param number number of arguments
|
||||
*
|
||||
* @return RefConstructor
|
||||
*
|
||||
* @throws RuntimeException if constructor not found
|
||||
*/
|
||||
public RefConstructor findConstructor(final int number) {
|
||||
final List<Constructor> constructors = new ArrayList<>();
|
||||
Collections.addAll(constructors, this.clazz.getConstructors());
|
||||
Collections.addAll(constructors, this.clazz.getDeclaredConstructors());
|
||||
for (final Constructor m : constructors) {
|
||||
if (m.getParameterTypes().length == number) {
|
||||
return new RefConstructor(m);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such constructor");
|
||||
}
|
||||
|
||||
/**
|
||||
* get field by name
|
||||
*
|
||||
* @param name field name
|
||||
*
|
||||
* @return RefField
|
||||
*
|
||||
* @throws RuntimeException if field not found
|
||||
*/
|
||||
public RefField getField(final String name) {
|
||||
try {
|
||||
try {
|
||||
return new RefField(this.clazz.getField(name));
|
||||
} catch (final NoSuchFieldException ignored) {
|
||||
return new RefField(this.clazz.getDeclaredField(name));
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* find field by type
|
||||
*
|
||||
* @param type field type
|
||||
*
|
||||
* @return RefField
|
||||
*
|
||||
* @throws RuntimeException if field not found
|
||||
*/
|
||||
public RefField findField(final RefClass type) {
|
||||
return findField(type.clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* find field by type
|
||||
*
|
||||
* @param type field type
|
||||
*
|
||||
* @return RefField
|
||||
*
|
||||
* @throws RuntimeException if field not found
|
||||
*/
|
||||
public RefField findField(Class type) {
|
||||
if (type == null) {
|
||||
type = void.class;
|
||||
}
|
||||
final List<Field> fields = new ArrayList<>();
|
||||
Collections.addAll(fields, this.clazz.getFields());
|
||||
Collections.addAll(fields, this.clazz.getDeclaredFields());
|
||||
for (final Field f : fields) {
|
||||
if (type.equals(f.getType())) {
|
||||
return new RefField(f);
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("no such field");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Method wrapper
|
||||
*/
|
||||
public static class RefMethod {
|
||||
private final Method method;
|
||||
|
||||
private RefMethod(final Method method) {
|
||||
this.method = method;
|
||||
method.setAccessible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return passed method
|
||||
*/
|
||||
public Method getRealMethod() {
|
||||
return this.method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return owner class of method
|
||||
*/
|
||||
public RefClass getRefClass() {
|
||||
return new RefClass(this.method.getDeclaringClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return class of method return type
|
||||
*/
|
||||
public RefClass getReturnRefClass() {
|
||||
return new RefClass(this.method.getReturnType());
|
||||
}
|
||||
|
||||
/**
|
||||
* apply method to object
|
||||
*
|
||||
* @param e object to which the method is applied
|
||||
*
|
||||
* @return RefExecutor with method call(...)
|
||||
*/
|
||||
public RefExecutor of(final Object e) {
|
||||
return new RefExecutor(e);
|
||||
}
|
||||
|
||||
/**
|
||||
* call static method
|
||||
*
|
||||
* @param params sent parameters
|
||||
*
|
||||
* @return return value
|
||||
*/
|
||||
public Object call(final Object... params) {
|
||||
try {
|
||||
return this.method.invoke(null, params);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public class RefExecutor {
|
||||
final Object e;
|
||||
|
||||
public RefExecutor(final Object e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* apply method for selected object
|
||||
*
|
||||
* @param params sent parameters
|
||||
*
|
||||
* @return return value
|
||||
*
|
||||
* @throws RuntimeException if something went wrong
|
||||
*/
|
||||
public Object call(final Object... params) {
|
||||
try {
|
||||
return RefMethod.this.method.invoke(this.e, params);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor wrapper
|
||||
*/
|
||||
public static class RefConstructor {
|
||||
private final Constructor constructor;
|
||||
|
||||
private RefConstructor(final Constructor constructor) {
|
||||
this.constructor = constructor;
|
||||
constructor.setAccessible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return passed constructor
|
||||
*/
|
||||
public Constructor getRealConstructor() {
|
||||
return this.constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return owner class of method
|
||||
*/
|
||||
public RefClass getRefClass() {
|
||||
return new RefClass(this.constructor.getDeclaringClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* create new instance with constructor
|
||||
*
|
||||
* @param params parameters for constructor
|
||||
*
|
||||
* @return new object
|
||||
*
|
||||
* @throws RuntimeException if something went wrong
|
||||
*/
|
||||
public Object create(final Object... params) {
|
||||
try {
|
||||
return this.constructor.newInstance(params);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class RefField {
|
||||
private final Field field;
|
||||
|
||||
private RefField(final Field field) {
|
||||
this.field = field;
|
||||
field.setAccessible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return passed field
|
||||
*/
|
||||
public Field getRealField() {
|
||||
return this.field;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return owner class of field
|
||||
*/
|
||||
public RefClass getRefClass() {
|
||||
return new RefClass(this.field.getDeclaringClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return type of field
|
||||
*/
|
||||
public RefClass getFieldRefClass() {
|
||||
return new RefClass(this.field.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* apply fiend for object
|
||||
*
|
||||
* @param e applied object
|
||||
*
|
||||
* @return RefExecutor with getter and setter
|
||||
*/
|
||||
public RefExecutor of(final Object e) {
|
||||
return new RefExecutor(e);
|
||||
}
|
||||
|
||||
public class RefExecutor {
|
||||
final Object e;
|
||||
|
||||
public RefExecutor(final Object e) {
|
||||
this.e = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* set field value for applied object
|
||||
*
|
||||
* @param param value
|
||||
*/
|
||||
public void set(final Object param) {
|
||||
try {
|
||||
RefField.this.field.set(this.e, param);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get field value for applied object
|
||||
*
|
||||
* @return value of field
|
||||
*/
|
||||
public Object get() {
|
||||
try {
|
||||
return RefField.this.field.get(this.e);
|
||||
} catch (final Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,562 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.intellectualcrafters.jnbt.ByteArrayTag;
|
||||
import com.intellectualcrafters.jnbt.CompoundTag;
|
||||
import com.intellectualcrafters.jnbt.IntTag;
|
||||
import com.intellectualcrafters.jnbt.ListTag;
|
||||
import com.intellectualcrafters.jnbt.NBTInputStream;
|
||||
import com.intellectualcrafters.jnbt.NBTOutputStream;
|
||||
import com.intellectualcrafters.jnbt.ShortTag;
|
||||
import com.intellectualcrafters.jnbt.StringTag;
|
||||
import com.intellectualcrafters.jnbt.Tag;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.config.Settings;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.intellectualcrafters.plot.object.schematic.PlotItem;
|
||||
import com.intellectualcrafters.plot.object.schematic.StateWrapper;
|
||||
import com.intellectualcrafters.plot.util.bukkit.BukkitUtil;
|
||||
import com.intellectualcrafters.plot.util.bukkit.UUIDHandler;
|
||||
|
||||
public abstract class SchematicHandler {
|
||||
public static SchematicHandler manager = new BukkitSchematicHandler();
|
||||
|
||||
private boolean exportAll = false;
|
||||
|
||||
public boolean exportAll(final Collection<Plot> collection, final File outputDir, final String namingScheme, final Runnable ifSuccess) {
|
||||
if (exportAll) {
|
||||
return false;
|
||||
}
|
||||
if (collection.size() == 0) {
|
||||
return false;
|
||||
}
|
||||
exportAll = true;
|
||||
final ArrayList<Plot> plots = new ArrayList<Plot>(collection);
|
||||
TaskManager.index.increment();
|
||||
final Integer currentIndex = TaskManager.index.toInteger();
|
||||
final int task = TaskManager.runTaskRepeat(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (plots.size() == 0) {
|
||||
exportAll = false;
|
||||
Bukkit.getScheduler().cancelTask(TaskManager.tasks.get(currentIndex));
|
||||
TaskManager.tasks.remove(currentIndex);
|
||||
TaskManager.runTask(ifSuccess);
|
||||
return;
|
||||
}
|
||||
Iterator<Plot> i = plots.iterator();
|
||||
final Plot plot = i.next();
|
||||
i.remove();
|
||||
String o = UUIDHandler.getName(plot.owner);
|
||||
if (o == null) {
|
||||
o = "unknown";
|
||||
}
|
||||
final String name;
|
||||
if (namingScheme == null) {
|
||||
name = plot.id.x + ";" + plot.id.y + "," + plot.world + "," + o;
|
||||
}
|
||||
else {
|
||||
name = namingScheme.replaceAll("%owner%", o).replaceAll("%id%", plot.id.toString()).replaceAll("%idx%", plot.id.x + "").replaceAll("%idy%", plot.id.y + "").replaceAll("%world%", plot.world);
|
||||
}
|
||||
final String directory;
|
||||
if (outputDir == null) {
|
||||
directory = Settings.SCHEMATIC_SAVE_PATH;
|
||||
}
|
||||
else {
|
||||
directory = outputDir.getPath();
|
||||
}
|
||||
if (PS.get().worldEdit != null) {
|
||||
new WorldEditSchematic().saveSchematic(directory + File.separator + name + ".schematic", plot.world, plot.id);
|
||||
}
|
||||
else {
|
||||
final CompoundTag sch = SchematicHandler.manager.getCompoundTag(plot.world, plot.id);
|
||||
if (sch == null) {
|
||||
MainUtil.sendMessage(null, "&7 - Skipped plot &c" + plot.id);
|
||||
} else {
|
||||
TaskManager.runTaskAsync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
MainUtil.sendMessage(null, "&6ID: " + plot.id);
|
||||
final boolean result = SchematicHandler.manager.save(sch, directory + File.separator + name + ".schematic");
|
||||
if (!result) {
|
||||
MainUtil.sendMessage(null, "&7 - Failed to save &c" + plot.id);
|
||||
} else {
|
||||
MainUtil.sendMessage(null, "&7 - &a success: " + plot.id);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 20);
|
||||
TaskManager.tasks.put(currentIndex, task);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Paste a schematic
|
||||
*
|
||||
* @param schematic the schematic object to paste
|
||||
* @param plot plot to paste in
|
||||
* @param x_offset offset x to paste it from plot origin
|
||||
* @param z_offset offset z to paste it from plot origin
|
||||
*
|
||||
* @return boolean true if succeeded
|
||||
*/
|
||||
public boolean paste(final Schematic schematic, final Plot plot, final int x_offset, final int z_offset) {
|
||||
if (schematic == null) {
|
||||
PS.log("Schematic == null :|");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
final Dimension demensions = schematic.getSchematicDimension();
|
||||
final int WIDTH = demensions.getX();
|
||||
final int LENGTH = demensions.getZ();
|
||||
final int HEIGHT = demensions.getY();
|
||||
final DataCollection[] blocks = schematic.getBlockCollection();
|
||||
Location l1 = MainUtil.getPlotBottomLoc(plot.world, plot.getId());
|
||||
final int sy = BukkitUtil.getHeighestBlock(plot.world, l1.getX() + 1, l1.getZ() + 1);
|
||||
if (!(HEIGHT == BukkitUtil.getMaxHeight(plot.world))) {
|
||||
l1 = l1.add(1, sy - 1, 1);
|
||||
}
|
||||
else {
|
||||
l1 = l1.add(1, 0, 1);
|
||||
}
|
||||
int X = l1.getX();
|
||||
int Y = l1.getY();
|
||||
int Z = l1.getZ();
|
||||
final int[] xl = new int[blocks.length];
|
||||
final int[] yl = new int[blocks.length];
|
||||
final int[] zl = new int[blocks.length];
|
||||
final int[] ids = new int[blocks.length];
|
||||
final byte[] data = new byte[blocks.length];
|
||||
for (int x = 0; x < WIDTH; x++) {
|
||||
for (int z = 0; z < LENGTH; z++) {
|
||||
for (int y = 0; y < HEIGHT; y++) {
|
||||
final int index = (y * WIDTH * LENGTH) + (z * WIDTH) + x;
|
||||
final DataCollection block = blocks[index];
|
||||
xl[index] = x + X;
|
||||
yl[index] = y + Y;
|
||||
zl[index] = z + Z;
|
||||
ids[index] = block.block;
|
||||
data[index] = block.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
BlockManager.setBlocks(plot.world, xl, yl, zl, ids, data);
|
||||
pasteStates(schematic, plot, x_offset, z_offset);
|
||||
} catch (final Exception e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean pasteStates(final Schematic schematic, final Plot plot, final int x_offset, final int z_offset) {
|
||||
if (schematic == null) {
|
||||
PS.log("Schematic == null :|");
|
||||
return false;
|
||||
}
|
||||
HashSet<PlotItem> items = schematic.getItems();
|
||||
if (items == null) {
|
||||
return false;
|
||||
}
|
||||
Location l1 = MainUtil.getPlotBottomLoc(plot.world, plot.getId());
|
||||
final int sy = BukkitUtil.getHeighestBlock(plot.world, l1.getX() + 1, l1.getZ() + 1);
|
||||
final Dimension demensions = schematic.getSchematicDimension();
|
||||
final int HEIGHT = demensions.getY();
|
||||
if (!(HEIGHT == BukkitUtil.getMaxHeight(plot.world))) {
|
||||
l1 = l1.add(1, sy - 1, 1);
|
||||
} else {
|
||||
l1 = l1.add(1, 0, 1);
|
||||
}
|
||||
int X = l1.getX() + x_offset;
|
||||
int Y = l1.getY();
|
||||
int Z = l1.getZ() + z_offset;
|
||||
for (PlotItem item : items) {
|
||||
item.x += X;
|
||||
item.y += Y;
|
||||
item.z += Z;
|
||||
BlockManager.manager.addItems(plot.world, item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Schematic getSchematic(final CompoundTag tag, final File file) {
|
||||
final Map<String, Tag> tagMap = tag.getValue();
|
||||
byte[] addId = new byte[0];
|
||||
if (tagMap.containsKey("AddBlocks")) {
|
||||
addId = ByteArrayTag.class.cast(tagMap.get("AddBlocks")).getValue();
|
||||
}
|
||||
final short width = ShortTag.class.cast(tagMap.get("Width")).getValue();
|
||||
final short length = ShortTag.class.cast(tagMap.get("Length")).getValue();
|
||||
final short height = ShortTag.class.cast(tagMap.get("Height")).getValue();
|
||||
final byte[] b = ByteArrayTag.class.cast(tagMap.get("Blocks")).getValue();
|
||||
final byte[] d = ByteArrayTag.class.cast(tagMap.get("Data")).getValue();
|
||||
final short[] blocks = new short[b.length];
|
||||
final Dimension dimension = new Dimension(width, height, length);
|
||||
for (int index = 0; index < b.length; index++) {
|
||||
if ((index >> 1) >= addId.length) {
|
||||
blocks[index] = (short) (b[index] & 0xFF);
|
||||
} else {
|
||||
if ((index & 1) == 0) {
|
||||
blocks[index] = (short) (((addId[index >> 1] & 0x0F) << 8) + (b[index] & 0xFF));
|
||||
} else {
|
||||
blocks[index] = (short) (((addId[index >> 1] & 0xF0) << 4) + (b[index] & 0xFF));
|
||||
}
|
||||
}
|
||||
}
|
||||
final DataCollection[] collection = new DataCollection[b.length];
|
||||
for (int x = 0; x < b.length; x++) {
|
||||
collection[x] = new DataCollection(blocks[x], d[x]);
|
||||
}
|
||||
Schematic schem = new Schematic(collection, dimension, file);
|
||||
try {
|
||||
List<Tag> blockStates = ListTag.class.cast(tagMap.get("TileEntities")).getValue();
|
||||
for (Tag stateTag : blockStates) {
|
||||
CompoundTag ct = ((CompoundTag) stateTag);
|
||||
Map<String, Tag> state = ct.getValue();
|
||||
short x = IntTag.class.cast(state.get("x")).getValue().shortValue();
|
||||
short y = IntTag.class.cast(state.get("y")).getValue().shortValue();
|
||||
short z = IntTag.class.cast(state.get("z")).getValue().shortValue();
|
||||
new StateWrapper(ct).restoreTag(x, y, z, schem);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return schem;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a schematic
|
||||
*
|
||||
* @param name to check
|
||||
*
|
||||
* @return schematic if found, else null
|
||||
*/
|
||||
public Schematic getSchematic(final String name) {
|
||||
{
|
||||
final File parent = new File(PS.get().IMP.getDirectory() + File.separator + "schematics");
|
||||
if (!parent.exists()) {
|
||||
if (!parent.mkdir()) {
|
||||
throw new RuntimeException("Could not create schematic parent directory");
|
||||
}
|
||||
}
|
||||
}
|
||||
final File file = new File(PS.get().IMP.getDirectory() + File.separator + "schematics" + File.separator + name + ".schematic");
|
||||
return getSchematic(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a schematic
|
||||
*
|
||||
* @param name to check
|
||||
*
|
||||
* @return schematic if found, else null
|
||||
*/
|
||||
public Schematic getSchematic(File file) {
|
||||
if (!file.exists()) {
|
||||
PS.log(file.toString() + " doesn't exist");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
final InputStream iStream = new FileInputStream(file);
|
||||
final NBTInputStream stream = new NBTInputStream(new GZIPInputStream(iStream));
|
||||
final CompoundTag tag = (CompoundTag) stream.readTag();
|
||||
stream.close();
|
||||
return getSchematic(tag, file);
|
||||
} catch (final Exception e) {
|
||||
PS.log(file.toString() + " is not in GZIP format");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public URL upload(final CompoundTag tag) {
|
||||
if (tag == null) {
|
||||
PS.log("&cCannot save empty tag");
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
String website = Settings.WEB_URL + "upload.php?" + uuid;
|
||||
String charset = "UTF-8";
|
||||
String param = "value";
|
||||
String boundary = Long.toHexString(System.currentTimeMillis());
|
||||
String CRLF = "\r\n";
|
||||
URLConnection con = new URL(website).openConnection();
|
||||
con.setDoOutput(true);
|
||||
con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
||||
try (
|
||||
OutputStream output = con.getOutputStream();
|
||||
PrintWriter writer = new PrintWriter(new OutputStreamWriter(output, charset), true);
|
||||
) {
|
||||
writer.append("--" + boundary).append(CRLF);
|
||||
writer.append("Content-Disposition: form-data; name=\"param\"").append(CRLF);
|
||||
writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF);
|
||||
writer.append(CRLF).append(param).append(CRLF).flush();
|
||||
writer.append("--" + boundary).append(CRLF);
|
||||
writer.append("Content-Disposition: form-data; name=\"schematicFile\"; filename=\"" + "plot.schematic" + "\"").append(CRLF);
|
||||
writer.append("Content-Type: " + URLConnection.guessContentTypeFromName("plot.schematic")).append(CRLF);
|
||||
writer.append("Content-Transfer-Encoding: binary").append(CRLF);
|
||||
writer.append(CRLF).flush();
|
||||
GZIPOutputStream gzip = new GZIPOutputStream(output);
|
||||
NBTOutputStream nos = new NBTOutputStream(gzip);
|
||||
nos.writeTag(tag);
|
||||
gzip.finish();
|
||||
nos.flush();
|
||||
output.flush();
|
||||
writer.append(CRLF).flush();
|
||||
writer.append("--" + boundary + "--").append(CRLF).flush();
|
||||
nos.close();
|
||||
output.close();
|
||||
}
|
||||
int responseCode = ((HttpURLConnection) con).getResponseCode();
|
||||
if (responseCode != 200) {
|
||||
return null;
|
||||
}
|
||||
return new URL(Settings.WEB_URL + "?key=" + uuid + "&ip=" + Settings.WEB_IP);
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves a schematic to a file path
|
||||
*
|
||||
* @param tag to save
|
||||
* @param path to save in
|
||||
*
|
||||
* @return true if succeeded
|
||||
*/
|
||||
public boolean save(final CompoundTag tag, final String path) {
|
||||
if (tag == null) {
|
||||
PS.log("&cCannot save empty tag");
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
final File tmp = new File(path);
|
||||
tmp.getParentFile().mkdirs();
|
||||
final OutputStream stream = new FileOutputStream(path);
|
||||
final NBTOutputStream output = new NBTOutputStream(new GZIPOutputStream(stream));
|
||||
output.writeTag(tag);
|
||||
output.close();
|
||||
stream.close();
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a compound tag from blocks
|
||||
* - Untested
|
||||
* @param blocks
|
||||
* @param blockdata
|
||||
* @param d
|
||||
* @return
|
||||
*/
|
||||
public CompoundTag createTag(byte[] blocks, byte[] blockdata, Dimension d) {
|
||||
final HashMap<String, Tag> schematic = new HashMap<>();
|
||||
schematic.put("Width", new ShortTag("Width", (short) d.getX()));
|
||||
schematic.put("Length", new ShortTag("Length", (short) d.getZ()));
|
||||
schematic.put("Height", new ShortTag("Height", (short) d.getY()));
|
||||
schematic.put("Materials", new StringTag("Materials", "Alpha"));
|
||||
schematic.put("WEOriginX", new IntTag("WEOriginX", 0));
|
||||
schematic.put("WEOriginY", new IntTag("WEOriginY", 0));
|
||||
schematic.put("WEOriginZ", new IntTag("WEOriginZ", 0));
|
||||
schematic.put("WEOffsetX", new IntTag("WEOffsetX", 0));
|
||||
schematic.put("WEOffsetY", new IntTag("WEOffsetY", 0));
|
||||
schematic.put("WEOffsetZ", new IntTag("WEOffsetZ", 0));
|
||||
schematic.put("Blocks", new ByteArrayTag("Blocks", blocks));
|
||||
schematic.put("Data", new ByteArrayTag("Data", blockdata));
|
||||
schematic.put("Entities", new ListTag("Entities", CompoundTag.class, new ArrayList<Tag>()));
|
||||
schematic.put("TileEntities", new ListTag("TileEntities", CompoundTag.class, new ArrayList<Tag>()));
|
||||
return new CompoundTag("Schematic", schematic);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the schematic of a plot
|
||||
*
|
||||
* @param world to check
|
||||
* @param id plot
|
||||
*
|
||||
* @return tag
|
||||
*/
|
||||
public CompoundTag getCompoundTag(final String world, final PlotId id) {
|
||||
if (!PS.get().getPlots(world).containsKey(id)) {
|
||||
return null;
|
||||
}
|
||||
final Location pos1 = MainUtil.getPlotBottomLoc(world, id).add(1, 0, 1);
|
||||
final Location pos2 = MainUtil.getPlotTopLoc(world, id);
|
||||
return getCompoundTag(world, pos1, pos2);
|
||||
}
|
||||
|
||||
public abstract CompoundTag getCompoundTag(final String world, final Location pos1, final Location pos2);
|
||||
|
||||
public boolean pastePart(final String world, final DataCollection[] blocks, final Location l1, final int x_offset, final int z_offset, final int i1, final int i2, final int WIDTH, final int LENGTH) {
|
||||
int length = 0;
|
||||
for (int i = i1; i <= i2; i++) {
|
||||
if (blocks[i].block == 0) {
|
||||
length++;
|
||||
}
|
||||
}
|
||||
length = i2 - i1 - length + 1;
|
||||
|
||||
int X = l1.getX();
|
||||
int Y = l1.getY();
|
||||
int Z = l1.getZ();
|
||||
|
||||
final int[] xl = new int[length];
|
||||
final int[] yl = new int[length];
|
||||
final int[] zl = new int[length];
|
||||
final int[] ids = new int[length];
|
||||
final byte[] data = new byte[length];
|
||||
int count = 0;
|
||||
for (int i = i1; i <= i2; i++) {
|
||||
final short id = blocks[i].block;
|
||||
if (id == 0) {
|
||||
continue; //
|
||||
}
|
||||
final int area = WIDTH * LENGTH;
|
||||
final int r = i % (area);
|
||||
final int x = r % WIDTH;
|
||||
final int y = i / area;
|
||||
final int z = r / WIDTH;
|
||||
xl[count] = x + X;
|
||||
yl[count] = y + Y;
|
||||
zl[count] = z + Z;
|
||||
ids[count] = id;
|
||||
data[count] = blocks[i].data;
|
||||
count++;
|
||||
if (y > 256) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
BlockManager.setBlocks(world, xl, yl, zl, ids, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Schematic Class
|
||||
*
|
||||
* @author Citymonstret
|
||||
*/
|
||||
public class Schematic {
|
||||
private final DataCollection[] blockCollection;
|
||||
private final Dimension schematicDimension;
|
||||
private final File file;
|
||||
private HashSet<PlotItem> items;
|
||||
|
||||
public Schematic(final DataCollection[] blockCollection, final Dimension schematicDimension, final File file) {
|
||||
this.blockCollection = blockCollection;
|
||||
this.schematicDimension = schematicDimension;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public void addItem(PlotItem item) {
|
||||
if (this.items == null) {
|
||||
this.items = new HashSet<>();
|
||||
}
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
public HashSet<PlotItem> getItems() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
public File getFile() {
|
||||
return this.file;
|
||||
}
|
||||
|
||||
public Dimension getSchematicDimension() {
|
||||
return this.schematicDimension;
|
||||
}
|
||||
|
||||
public DataCollection[] getBlockCollection() {
|
||||
return this.blockCollection;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schematic Dimensions
|
||||
*
|
||||
* @author Citymonstret
|
||||
*/
|
||||
public static class Dimension {
|
||||
private final int x;
|
||||
private final int y;
|
||||
private final int z;
|
||||
|
||||
public Dimension(final int x, final int y, final int z) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public int getX() {
|
||||
return this.x;
|
||||
}
|
||||
|
||||
public int getY() {
|
||||
return this.y;
|
||||
}
|
||||
|
||||
public int getZ() {
|
||||
return this.z;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Schematic Data Collection
|
||||
*
|
||||
* @author Citymonstret
|
||||
*/
|
||||
public class DataCollection {
|
||||
private final short block;
|
||||
private final byte data;
|
||||
|
||||
// public CompoundTag tag;
|
||||
public DataCollection(final short block, final byte data) {
|
||||
this.block = block;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public short getBlock() {
|
||||
return this.block;
|
||||
}
|
||||
|
||||
public byte getData() {
|
||||
return this.data;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,273 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.generator.AugmentedPopulator;
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.object.PlotBlock;
|
||||
|
||||
public class SetBlockQueue {
|
||||
|
||||
private volatile static HashMap<ChunkWrapper, PlotBlock[][]> blocks;
|
||||
private volatile static int allocate = 25;
|
||||
private volatile static boolean running = false;
|
||||
private volatile static boolean locked = false;
|
||||
private volatile static HashSet<Runnable> runnables;
|
||||
private volatile static boolean slow = false;
|
||||
private static long last;
|
||||
private static int lastInt = 0;
|
||||
private static PlotBlock lastBlock = new PlotBlock((short) 0, (byte) 0);
|
||||
|
||||
public synchronized static void allocate(int t) {
|
||||
allocate = t;
|
||||
}
|
||||
|
||||
public static int getAllocate() {
|
||||
return allocate;
|
||||
}
|
||||
|
||||
public static void setSlow(boolean value) {
|
||||
slow = value;
|
||||
}
|
||||
|
||||
public synchronized static void addNotify(Runnable whenDone) {
|
||||
if (runnables == null) {
|
||||
TaskManager.runTask(whenDone);
|
||||
slow = false;
|
||||
locked = false;
|
||||
}
|
||||
else {
|
||||
runnables.add(whenDone);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized static void init() {
|
||||
if (blocks == null) {
|
||||
if (AugmentedPopulator.x_loc == null) {
|
||||
AugmentedPopulator.initCache();
|
||||
}
|
||||
blocks = new HashMap<>();
|
||||
runnables = new HashSet<>();
|
||||
}
|
||||
if (!running) {
|
||||
TaskManager.index.increment();
|
||||
final int current = TaskManager.index.intValue();
|
||||
int task = TaskManager.runTaskRepeat(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (locked) {
|
||||
return;
|
||||
}
|
||||
if (blocks.size() == 0) {
|
||||
PS.get().TASK.cancelTask(TaskManager.tasks.get(current));
|
||||
for (Runnable runnable : runnables) {
|
||||
TaskManager.runTask(runnable);
|
||||
}
|
||||
runnables = null;
|
||||
blocks = null;
|
||||
running = false;
|
||||
slow = false;
|
||||
return;
|
||||
}
|
||||
long newLast = System.currentTimeMillis();
|
||||
last = Math.max(newLast - 100, last);
|
||||
while (blocks.size() > 0 && (System.currentTimeMillis() - last < 100 + allocate)) {
|
||||
if (locked) {
|
||||
return;
|
||||
}
|
||||
Entry<ChunkWrapper, PlotBlock[][]> n = blocks.entrySet().iterator().next();
|
||||
ChunkWrapper chunk = n.getKey();
|
||||
PlotBlock[][] blocks = n.getValue();
|
||||
int X = chunk.x << 4;
|
||||
int Z = chunk.z << 4;
|
||||
String world = chunk.world;
|
||||
if (slow) {
|
||||
boolean once = false;
|
||||
for (int j = 0; j < blocks.length; j++) {
|
||||
PlotBlock[] blocksj = blocks[j];
|
||||
if (blocksj != null) {
|
||||
long start = System.currentTimeMillis();
|
||||
for (int k = 0; k < blocksj.length; k++) {
|
||||
if (once && (System.currentTimeMillis() - start > allocate)) {
|
||||
SetBlockQueue.blocks.put(n.getKey(), blocks);
|
||||
return;
|
||||
}
|
||||
PlotBlock block = blocksj[k];
|
||||
if (block != null) {
|
||||
int x = AugmentedPopulator.x_loc[j][k];
|
||||
int y = AugmentedPopulator.y_loc[j][k];
|
||||
int z = AugmentedPopulator.z_loc[j][k];
|
||||
BlockManager.manager.functionSetBlock(world, X + x, y, Z + z, block.id, block.data);
|
||||
blocks[j][k] = null;
|
||||
once = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SetBlockQueue.blocks.remove(n.getKey());
|
||||
return;
|
||||
}
|
||||
SetBlockQueue.blocks.remove(n.getKey());
|
||||
for (int j = 0; j < blocks.length; j++) {
|
||||
PlotBlock[] blocksj = blocks[j];
|
||||
if (blocksj != null) {
|
||||
for (int k = 0; k < blocksj.length; k++) {
|
||||
PlotBlock block = blocksj[k];
|
||||
if (block != null) {
|
||||
int x = AugmentedPopulator.x_loc[j][k];
|
||||
int y = AugmentedPopulator.y_loc[j][k];
|
||||
int z = AugmentedPopulator.z_loc[j][k];
|
||||
BlockManager.manager.functionSetBlock(world, X + x, y, Z + z, block.id, block.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 2);
|
||||
TaskManager.tasks.put(current, task);
|
||||
running = true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setChunk(final String world, ChunkLoc loc, PlotBlock[][] result) {
|
||||
locked = true;
|
||||
if (!running) {
|
||||
init();
|
||||
}
|
||||
ChunkWrapper wrap = new ChunkWrapper(world, loc.x, loc.z);
|
||||
blocks.put(wrap, result);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
public static void setBlock(final String world, int x, final int y, int z, final PlotBlock block) {
|
||||
locked = true;
|
||||
if (!running) {
|
||||
init();
|
||||
}
|
||||
int X = x >> 4;
|
||||
int Z = z >> 4;
|
||||
x -= X << 4;
|
||||
z -= Z << 4;
|
||||
|
||||
ChunkWrapper wrap = new ChunkWrapper(world, X, Z);
|
||||
PlotBlock[][] result;
|
||||
result = blocks.get(wrap);
|
||||
if (!blocks.containsKey(wrap)) {
|
||||
result = new PlotBlock[16][];
|
||||
blocks.put(wrap, result);
|
||||
}
|
||||
|
||||
if (result[y >> 4] == null) {
|
||||
result[y >> 4] = new PlotBlock[4096];
|
||||
}
|
||||
result[y >> 4][((y & 0xF) << 8) | (z << 4) | x] = block;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
public static void setData(final String world, int x, final int y, int z, final byte data) {
|
||||
locked = true;
|
||||
if (!running) {
|
||||
init();
|
||||
}
|
||||
int X = x >> 4;
|
||||
int Z = z >> 4;
|
||||
x -= X << 4;
|
||||
z -= Z << 4;
|
||||
ChunkWrapper wrap = new ChunkWrapper(world, X, Z);
|
||||
PlotBlock[][] result;
|
||||
result = blocks.get(wrap);
|
||||
if (!blocks.containsKey(wrap)) {
|
||||
result = new PlotBlock[16][];
|
||||
blocks.put(wrap, result);
|
||||
}
|
||||
if (result[y >> 4] == null) {
|
||||
result[y >> 4] = new PlotBlock[4096];
|
||||
}
|
||||
result[y >> 4][((y & 0xF) << 8) | (z << 4) | x] = new PlotBlock((short) -1, data);
|
||||
locked = false;
|
||||
}
|
||||
|
||||
public static void setBlock(final String world, int x, final int y, int z, final int id) {
|
||||
locked = true;
|
||||
if (!running) {
|
||||
init();
|
||||
}
|
||||
int X = x >> 4;
|
||||
int Z = z >> 4;
|
||||
x -= X << 4;
|
||||
z -= Z << 4;
|
||||
ChunkWrapper wrap = new ChunkWrapper(world, X, Z);
|
||||
PlotBlock[][] result;
|
||||
result = blocks.get(wrap);
|
||||
if (!blocks.containsKey(wrap)) {
|
||||
result = new PlotBlock[16][];
|
||||
blocks.put(wrap, result);
|
||||
}
|
||||
if (result[y >> 4] == null) {
|
||||
result[y >> 4] = new PlotBlock[4096];
|
||||
}
|
||||
if (id == lastInt) {
|
||||
result[y >> 4][((y & 0xF) << 8) | (z << 4) | x] = lastBlock;
|
||||
}
|
||||
else {
|
||||
lastInt = id;
|
||||
lastBlock = new PlotBlock((short) id, (byte) 0);
|
||||
}
|
||||
result[y >> 4][((y & 0xF) << 8) | (z << 4) | x] = lastBlock;
|
||||
locked = false;
|
||||
}
|
||||
|
||||
public static class ChunkWrapper {
|
||||
public final int x;
|
||||
public final int z;
|
||||
public final String world;
|
||||
|
||||
public ChunkWrapper(String world, int x, int z) {
|
||||
this.world = world;
|
||||
this.x = x;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
if (this.x >= 0) {
|
||||
if (this.z >= 0) {
|
||||
result = (this.x * this.x) + (3 * this.x) + (2 * this.x * this.z) + this.z + (this.z * this.z);
|
||||
} else {
|
||||
final int y1 = -this.z;
|
||||
result = (this.x * this.x) + (3 * this.x) + (2 * this.x * y1) + y1 + (y1 * y1) + 1;
|
||||
}
|
||||
} else {
|
||||
final int x1 = -this.x;
|
||||
if (this.z >= 0) {
|
||||
result = -((x1 * x1) + (3 * x1) + (2 * x1 * this.z) + this.z + (this.z * this.z));
|
||||
} else {
|
||||
final int y1 = -this.z;
|
||||
result = -((x1 * x1) + (3 * x1) + (2 * x1 * y1) + y1 + (y1 * y1) + 1);
|
||||
}
|
||||
}
|
||||
result = result * 31 + world.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final ChunkWrapper other = (ChunkWrapper) obj;
|
||||
return ((this.x == other.x) && (this.z == other.z) && (this.world.equals(other.world)));
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
|
||||
import com.intellectualcrafters.plot.object.PlotWorld;
|
||||
import com.intellectualcrafters.plot.object.SetupObject;
|
||||
|
||||
public abstract class SetupUtils {
|
||||
|
||||
public static SetupUtils manager;
|
||||
|
||||
public final static Map<String, SetupObject> setupMap = new HashMap<>();
|
||||
public static HashMap<String, ChunkGenerator> generators = new HashMap<>();
|
||||
|
||||
public abstract void updateGenerators();
|
||||
|
||||
public abstract String getGenerator(PlotWorld plotworld);
|
||||
|
||||
public abstract String setupWorld(final SetupObject object);
|
||||
}
|
@ -0,0 +1,167 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
||||
/**
|
||||
* String comparison library
|
||||
*
|
||||
* @author Citymonstret
|
||||
* @author Empire92
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
public class StringComparison<T> {
|
||||
|
||||
private T bestMatch;
|
||||
private double match = Integer.MAX_VALUE;
|
||||
private T bestMatchObject;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param input Input Base Value
|
||||
* @param objects Objects to compare
|
||||
*/
|
||||
public StringComparison(String input, final T[] objects) {
|
||||
init(input, objects);
|
||||
}
|
||||
|
||||
/**
|
||||
* You should call init(...) when you are ready to get a String comparison value
|
||||
*/
|
||||
public StringComparison() {}
|
||||
|
||||
public void init(String input, final T[] objects) {
|
||||
int c;
|
||||
this.bestMatch = objects[0];
|
||||
this.bestMatchObject = objects[0];
|
||||
input = input.toLowerCase();
|
||||
for (final T o : objects) {
|
||||
if ((c = compare(input, o.toString().toLowerCase())) < this.match) {
|
||||
this.match = c;
|
||||
this.bestMatch = o;
|
||||
this.bestMatchObject = o;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare two strings
|
||||
*
|
||||
* @param s1 String Base
|
||||
* @param s2 Object
|
||||
*
|
||||
* @return match
|
||||
*/
|
||||
public static int compare(final String s1, final String s2) {
|
||||
int distance = StringUtils.getLevenshteinDistance(s1, s2);
|
||||
if (s2.contains(s1)) {
|
||||
distance -= (Math.min(s1.length(), s2.length()));
|
||||
}
|
||||
if (s2.startsWith(s1)) {
|
||||
distance -= 4;
|
||||
}
|
||||
return distance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an ArrayList containing pairs of letters
|
||||
*
|
||||
* @param s string to split
|
||||
*
|
||||
* @return ArrayList
|
||||
*/
|
||||
public static ArrayList<String> wLetterPair(final String s) {
|
||||
final ArrayList<String> aPairs = new ArrayList<>();
|
||||
final String[] wo = s.split("\\s");
|
||||
for (final String aWo : wo) {
|
||||
final String[] po = sLetterPair(aWo);
|
||||
Collections.addAll(aPairs, po);
|
||||
}
|
||||
return aPairs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an array containing letter pairs
|
||||
*
|
||||
* @param s string to split
|
||||
*
|
||||
* @return Array
|
||||
*/
|
||||
public static String[] sLetterPair(final String s) {
|
||||
final int numPair = s.length() - 1;
|
||||
final String[] p = new String[numPair];
|
||||
for (int i = 0; i < numPair; i++) {
|
||||
p[i] = s.substring(i, i + 2);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object
|
||||
*
|
||||
* @return match object
|
||||
*/
|
||||
public T getMatchObject() {
|
||||
return this.bestMatchObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the best match value
|
||||
*
|
||||
* @return match value
|
||||
*/
|
||||
public String getBestMatch() {
|
||||
return this.bestMatch.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Will return both the match number, and the actual match string
|
||||
*
|
||||
* @return object[] containing: double, String
|
||||
*/
|
||||
public ComparisonResult getBestMatchAdvanced() {
|
||||
return new ComparisonResult(this.match, this.bestMatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* The comparison result
|
||||
*/
|
||||
public class ComparisonResult {
|
||||
|
||||
public final T best;
|
||||
public final double match;
|
||||
|
||||
/**
|
||||
* The constructor
|
||||
* @param match Match value
|
||||
* @param best Best Match
|
||||
*/
|
||||
public ComparisonResult(final double match, final T best) {
|
||||
this.match = match;
|
||||
this.best = best;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
public class StringMan {
|
||||
public static String replaceFromMap(String string, Map<String, String> replacements) {
|
||||
StringBuilder sb = new StringBuilder(string);
|
||||
for (Entry<String, String> entry : replacements.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
String value = entry.getValue();
|
||||
|
||||
int start = sb.indexOf(key, 0);
|
||||
while (start > -1) {
|
||||
int end = start + key.length();
|
||||
int nextSearchStart = start + value.length();
|
||||
sb.replace(start, end, value);
|
||||
start = sb.indexOf(key, nextSearchStart);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.apache.commons.lang.mutable.MutableInt;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
|
||||
public abstract class TaskManager {
|
||||
public static HashSet<String> TELEPORT_QUEUE = new HashSet<>();
|
||||
|
||||
public static MutableInt index = new MutableInt(0);
|
||||
public static HashMap<Integer, Integer> tasks = new HashMap<>();
|
||||
|
||||
public static int runTaskRepeat(final Runnable r, final int interval) {
|
||||
if (r != null) {
|
||||
return PS.get().TASK.taskRepeat(r, interval);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static void runTaskAsync(final Runnable r) {
|
||||
if (r != null) {
|
||||
PS.get().TASK.taskAsync(r);
|
||||
}
|
||||
}
|
||||
|
||||
public static void runTask(final Runnable r) {
|
||||
if (r != null) {
|
||||
PS.get().TASK.task(r);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run task later (delay in ticks)
|
||||
* @param r
|
||||
* @param delay
|
||||
*/
|
||||
public static void runTaskLater(final Runnable r, final int delay) {
|
||||
if (r != null) {
|
||||
PS.get().TASK.taskLater(r, delay);
|
||||
}
|
||||
}
|
||||
|
||||
public static void runTaskLaterAsync(final Runnable r, final int delay) {
|
||||
if (r != null) {
|
||||
PS.get().TASK.taskLaterAsync(r, delay);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract int taskRepeat(final Runnable r, int interval);
|
||||
|
||||
public abstract void taskAsync(final Runnable r);
|
||||
|
||||
public abstract void task(final Runnable r);
|
||||
|
||||
public abstract void taskLater(final Runnable r, int delay);
|
||||
|
||||
public abstract void taskLaterAsync(final Runnable r, int delay);
|
||||
|
||||
public abstract void cancelTask(int task);
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package com.intellectualcrafters.plot.util;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.sk89q.worldedit.CuboidClipboard;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.Vector;
|
||||
import com.sk89q.worldedit.bukkit.BukkitWorld;
|
||||
|
||||
public class WorldEditSchematic {
|
||||
public void saveSchematic(String file, final String world, final PlotId id) {
|
||||
Location bot = MainUtil.getPlotBottomLoc(world, id).add(1, 0, 1);
|
||||
Location top = MainUtil.getPlotTopLoc(world, id);
|
||||
Vector size = new Vector(top.getX() - bot.getX() + 1, top.getY() - bot.getY() - 1, top.getZ() - bot.getZ() + 1);
|
||||
Vector origin = new Vector(bot.getX(), bot.getY(), bot.getZ());
|
||||
CuboidClipboard clipboard = new CuboidClipboard(size, origin);
|
||||
Vector pos1 = new Vector(bot.getX(), bot.getY(), bot.getZ());
|
||||
Vector pos2 = new Vector(top.getX(), top.getY(), top.getZ());
|
||||
EditSession session = PS.get().worldEdit.getWorldEdit().getEditSessionFactory().getEditSession(new BukkitWorld(Bukkit.getWorld(world)), 999999999);
|
||||
clipboard.copy(session);
|
||||
try {
|
||||
clipboard.saveSchematic(new File(file));
|
||||
MainUtil.sendMessage(null, "&7 - &a success: " + id);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
MainUtil.sendMessage(null, "&7 - Failed to save &c" + id);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,76 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import net.milkbowl.vault.economy.Economy;
|
||||
import net.milkbowl.vault.permission.Permission;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.RegisteredServiceProvider;
|
||||
|
||||
import com.intellectualcrafters.plot.object.BukkitOfflinePlayer;
|
||||
import com.intellectualcrafters.plot.object.BukkitPlayer;
|
||||
import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.util.EconHandler;
|
||||
|
||||
public class BukkitEconHandler extends EconHandler {
|
||||
|
||||
private Economy econ;
|
||||
private Permission perms;
|
||||
|
||||
public boolean init() {
|
||||
if (econ == null || perms == null) {
|
||||
setupPermissions();
|
||||
setupEconomy();
|
||||
}
|
||||
return econ != null && perms != null;
|
||||
}
|
||||
|
||||
private boolean setupPermissions()
|
||||
{
|
||||
RegisteredServiceProvider<Permission> permissionProvider = Bukkit.getServer().getServicesManager().getRegistration(net.milkbowl.vault.permission.Permission.class);
|
||||
if (permissionProvider != null) {
|
||||
perms = permissionProvider.getProvider();
|
||||
}
|
||||
return (perms != null);
|
||||
}
|
||||
|
||||
private boolean setupEconomy()
|
||||
{
|
||||
RegisteredServiceProvider<Economy> economyProvider = Bukkit.getServer().getServicesManager().getRegistration(net.milkbowl.vault.economy.Economy.class);
|
||||
if (economyProvider != null) {
|
||||
econ = economyProvider.getProvider();
|
||||
}
|
||||
|
||||
return (econ != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getMoney(PlotPlayer player) {
|
||||
return econ.getBalance(player.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void withdrawMoney(PlotPlayer player, double amount) {
|
||||
econ.withdrawPlayer(player.getName(), amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void depositMoney(PlotPlayer player, double amount) {
|
||||
econ.depositPlayer(player.getName(), amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void depositMoney(OfflinePlotPlayer player, double amount) {
|
||||
econ.depositPlayer(((BukkitOfflinePlayer) player).player, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermission(PlotPlayer player, String perm, boolean value) {
|
||||
if (value) {
|
||||
perms.playerAdd(((BukkitPlayer) player).player, perm);
|
||||
}
|
||||
else {
|
||||
perms.playerRemove(((BukkitPlayer) player).player, perm);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,118 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Cancellable;
|
||||
import org.bukkit.event.Event;
|
||||
|
||||
import com.intellectualcrafters.plot.events.ClusterFlagRemoveEvent;
|
||||
import com.intellectualcrafters.plot.events.PlayerClaimPlotEvent;
|
||||
import com.intellectualcrafters.plot.events.PlayerEnterPlotEvent;
|
||||
import com.intellectualcrafters.plot.events.PlayerLeavePlotEvent;
|
||||
import com.intellectualcrafters.plot.events.PlayerPlotDeniedEvent;
|
||||
import com.intellectualcrafters.plot.events.PlayerPlotHelperEvent;
|
||||
import com.intellectualcrafters.plot.events.PlayerPlotTrustedEvent;
|
||||
import com.intellectualcrafters.plot.events.PlayerTeleportToPlotEvent;
|
||||
import com.intellectualcrafters.plot.events.PlotClearEvent;
|
||||
import com.intellectualcrafters.plot.events.PlotDeleteEvent;
|
||||
import com.intellectualcrafters.plot.events.PlotFlagAddEvent;
|
||||
import com.intellectualcrafters.plot.events.PlotFlagRemoveEvent;
|
||||
import com.intellectualcrafters.plot.events.PlotMergeEvent;
|
||||
import com.intellectualcrafters.plot.events.PlotUnlinkEvent;
|
||||
import com.intellectualcrafters.plot.flag.Flag;
|
||||
import com.intellectualcrafters.plot.object.BukkitPlayer;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotCluster;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.util.EventUtil;
|
||||
|
||||
public class BukkitEventUtil extends EventUtil {
|
||||
|
||||
public Player getPlayer(PlotPlayer player) {
|
||||
return ((BukkitPlayer) player).player;
|
||||
}
|
||||
|
||||
public boolean callEvent(Event event) {
|
||||
Bukkit.getServer().getPluginManager().callEvent(event);
|
||||
if (event instanceof Cancellable) {
|
||||
return !((Cancellable) event).isCancelled();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callClaim(PlotPlayer player, Plot plot, boolean auto) {
|
||||
return callEvent(new PlayerClaimPlotEvent(getPlayer(player), plot, auto));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callTeleport(PlotPlayer player, Location from, Plot plot) {
|
||||
return callEvent(new PlayerTeleportToPlotEvent(getPlayer(player), from, plot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callClear(String world, PlotId id) {
|
||||
return callEvent(new PlotClearEvent(world, id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callDelete(String world, PlotId id) {
|
||||
callEvent(new PlotDeleteEvent(world, id));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callFlagAdd(Flag flag, Plot plot) {
|
||||
return callEvent(new PlotFlagAddEvent(flag, plot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callFlagRemove(Flag flag, Plot plot) {
|
||||
return callEvent(new PlotFlagRemoveEvent(flag, plot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callMerge(String world, Plot plot, ArrayList<PlotId> plots) {
|
||||
return callEvent(new PlotMergeEvent(BukkitUtil.getWorld(world), plot, plots));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callUnlink(String world, ArrayList<PlotId> plots) {
|
||||
return callEvent(new PlotUnlinkEvent(BukkitUtil.getWorld(world), plots));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callEntry(PlotPlayer player, Plot plot) {
|
||||
callEvent(new PlayerEnterPlotEvent(getPlayer(player), plot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callLeave(PlotPlayer player, Plot plot) {
|
||||
callEvent(new PlayerLeavePlotEvent(getPlayer(player), plot));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callDenied(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
|
||||
callEvent(new PlayerPlotDeniedEvent(getPlayer(initiator), plot, player, added));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callTrusted(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
|
||||
callEvent(new PlayerPlotHelperEvent(getPlayer(initiator), plot, player, added));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void callMember(PlotPlayer initiator, Plot plot, UUID player, boolean added) {
|
||||
callEvent(new PlayerPlotTrustedEvent(getPlayer(initiator), plot, player, added));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callFlagRemove(Flag flag, PlotCluster cluster) {
|
||||
return callEvent(new ClusterFlagRemoveEvent(flag, cluster));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.event.inventory.InventoryType;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
||||
import com.intellectualcrafters.plot.object.BukkitPlayer;
|
||||
import com.intellectualcrafters.plot.object.PlotInventory;
|
||||
import com.intellectualcrafters.plot.object.PlotItemStack;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.util.InventoryUtil;
|
||||
|
||||
public class BukkitInventoryUtil extends InventoryUtil {
|
||||
|
||||
@Override
|
||||
public void open(PlotInventory inv) {
|
||||
BukkitPlayer bp = ((BukkitPlayer) inv.player);
|
||||
Inventory inventory = Bukkit.createInventory(null, inv.size * 9, inv.getTitle());
|
||||
PlotItemStack[] items = inv.getItems();
|
||||
for (int i = 0; i < inv.size * 9; i++) {
|
||||
PlotItemStack item = items[i];
|
||||
if (item != null) {
|
||||
inventory.setItem(i, getItem(item));
|
||||
}
|
||||
}
|
||||
inv.player.setMeta("inventory", inv);
|
||||
bp.player.openInventory(inventory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(PlotInventory inv) {
|
||||
if (!inv.isOpen()) {
|
||||
return;
|
||||
}
|
||||
inv.player.deleteMeta("inventory");
|
||||
BukkitPlayer bp = ((BukkitPlayer) inv.player);
|
||||
bp.player.closeInventory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setItem(PlotInventory inv, int index, PlotItemStack item) {
|
||||
BukkitPlayer bp = ((BukkitPlayer) inv.player);
|
||||
InventoryView opened = bp.player.getOpenInventory();
|
||||
if (!inv.isOpen()) {
|
||||
return;
|
||||
}
|
||||
opened.setItem(index, getItem(item));
|
||||
bp.player.updateInventory();
|
||||
}
|
||||
|
||||
public PlotItemStack getItem(ItemStack item ) {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
int id = item.getTypeId();
|
||||
short data = item.getDurability();
|
||||
int amount = item.getAmount();
|
||||
String name = null;
|
||||
String[] lore = null;
|
||||
if (item.hasItemMeta()) {
|
||||
ItemMeta meta = item.getItemMeta();
|
||||
if (meta.hasDisplayName()) {
|
||||
name = meta.getDisplayName();
|
||||
}
|
||||
if (meta.hasLore()) {
|
||||
List<String> itemLore = meta.getLore();
|
||||
lore = itemLore.toArray(new String[itemLore.size()]);
|
||||
}
|
||||
}
|
||||
return new PlotItemStack(id, data, amount, name, lore);
|
||||
}
|
||||
|
||||
public static ItemStack getItem(PlotItemStack item) {
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
ItemStack stack = new ItemStack(item.id, item.amount, item.data);
|
||||
ItemMeta meta = null;
|
||||
if (item.name != null) {
|
||||
meta = stack.getItemMeta();
|
||||
meta.setDisplayName(ChatColor.translateAlternateColorCodes('&', item.name));
|
||||
}
|
||||
if (item.lore != null) {
|
||||
if (meta == null) {
|
||||
meta = stack.getItemMeta();
|
||||
}
|
||||
List<String> lore = new ArrayList<>();
|
||||
for (String entry : item.lore) {
|
||||
lore.add(ChatColor.translateAlternateColorCodes('&', entry));
|
||||
}
|
||||
meta.setLore(lore);
|
||||
}
|
||||
if (meta != null) {
|
||||
stack.setItemMeta(meta);
|
||||
}
|
||||
return stack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlotItemStack[] getItems(PlotPlayer player) {
|
||||
BukkitPlayer bp = ((BukkitPlayer) player);
|
||||
PlayerInventory inv = bp.player.getInventory();
|
||||
PlotItemStack[] items = new PlotItemStack[36];
|
||||
for (int i = 0; i < 36; i++) {
|
||||
items[i] = getItem(inv.getItem(i));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen(PlotInventory inv) {
|
||||
if (!inv.isOpen()) {
|
||||
return false;
|
||||
}
|
||||
BukkitPlayer bp = ((BukkitPlayer) inv.player);
|
||||
InventoryView opened = bp.player.getOpenInventory();
|
||||
return (inv.isOpen() && opened.getType() == InventoryType.CRAFTING && opened.getTitle() == null);
|
||||
}
|
||||
}
|
@ -0,0 +1,142 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotId;
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
|
||||
/**
|
||||
* Functions involving players, plots and locations.
|
||||
*/
|
||||
public class BukkitPlayerFunctions {
|
||||
|
||||
/*
|
||||
* =========== NOTICE ================
|
||||
* - We will try to move as many functions as we can out of this class and into the MainUtil class
|
||||
*/
|
||||
|
||||
/**
|
||||
* Clear a plot. Use null player if no player is present
|
||||
* @param player
|
||||
* @param world
|
||||
* @param plot
|
||||
* @param isDelete
|
||||
*/
|
||||
public static void clear(final Player player, final String world, final Plot plot, final boolean isDelete) {
|
||||
final long start = System.currentTimeMillis();
|
||||
final Runnable whenDone = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if ((player != null) && player.isOnline()) {
|
||||
MainUtil.sendMessage(BukkitUtil.getPlayer(player), C.CLEARING_DONE, "" + (System.currentTimeMillis() - start));
|
||||
}
|
||||
}
|
||||
};
|
||||
if (!MainUtil.clearAsPlayer(plot, isDelete, whenDone)) {
|
||||
MainUtil.sendMessage(null, C.WAIT_FOR_TIMER);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getPlayerName(final UUID uuid) {
|
||||
if (uuid == null) {
|
||||
return "unknown";
|
||||
}
|
||||
final String name = UUIDHandler.getName(uuid);
|
||||
if (name == null) {
|
||||
return "unknown";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param player player
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isInPlot(final Player player) {
|
||||
return getCurrentPlot(player) != null;
|
||||
}
|
||||
|
||||
public static ArrayList<PlotId> getMaxPlotSelectionIds(final String world, PlotId pos1, PlotId pos2) {
|
||||
final Plot plot1 = PS.get().getPlots(world).get(pos1);
|
||||
final Plot plot2 = PS.get().getPlots(world).get(pos2);
|
||||
if (plot1 != null) {
|
||||
pos1 = MainUtil.getBottomPlot(plot1).id;
|
||||
}
|
||||
if (plot2 != null) {
|
||||
pos2 = MainUtil.getTopPlot(plot2).id;
|
||||
}
|
||||
final ArrayList<PlotId> myplots = new ArrayList<>();
|
||||
for (int x = pos1.x; x <= pos2.x; x++) {
|
||||
for (int y = pos1.y; y <= pos2.y; y++) {
|
||||
myplots.add(new PlotId(x, y));
|
||||
}
|
||||
}
|
||||
return myplots;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plot a player is currently in.
|
||||
*
|
||||
* @param player
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static Plot getCurrentPlot(final Player player) {
|
||||
if (!PS.get().isPlotWorld(player.getWorld().getName())) {
|
||||
return null;
|
||||
}
|
||||
final PlotId id = MainUtil.getPlotId(BukkitUtil.getLocation(player));
|
||||
final String world = player.getWorld().getName();
|
||||
if (id == null) {
|
||||
return null;
|
||||
}
|
||||
if (PS.get().getPlots(world).containsKey(id)) {
|
||||
return PS.get().getPlots(world).get(id);
|
||||
}
|
||||
return new Plot(world, id, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the plots for a player
|
||||
*
|
||||
* @param plr
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public static Set<Plot> getPlayerPlots(final String world, final Player plr) {
|
||||
final Set<Plot> p = PS.get().getPlots(world, plr.getName());
|
||||
if (p == null) {
|
||||
return new HashSet<>();
|
||||
}
|
||||
return p;
|
||||
}
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import com.intellectualcrafters.plot.object.BukkitPlayer;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.util.PlayerManager;
|
||||
|
||||
public class BukkitPlayerManager extends PlayerManager {
|
||||
|
||||
@Override
|
||||
public void kickPlayer(PlotPlayer player, String reason) {
|
||||
((BukkitPlayer) player).player.kickPlayer(reason);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.util.BlockUpdateUtil;
|
||||
|
||||
public abstract class BukkitSetBlockManager extends BlockUpdateUtil {
|
||||
public static BukkitSetBlockManager setBlockManager = null;
|
||||
|
||||
public abstract void set(final org.bukkit.World world, final int x, final int y, final int z, final int blockId, final byte data);
|
||||
|
||||
public abstract void update(Collection<Chunk> list);
|
||||
|
||||
@Override
|
||||
public void update(final String worldname, final Collection<ChunkLoc> chunkLocs) {
|
||||
final World world = BukkitUtil.getWorld(worldname);
|
||||
final ArrayList<Chunk> chunks = new ArrayList<Chunk>();
|
||||
for (final ChunkLoc loc : chunkLocs) {
|
||||
chunks.add(world.getChunkAt(loc.x, loc.z));
|
||||
}
|
||||
setBlockManager.update(chunks);
|
||||
}
|
||||
}
|
@ -0,0 +1,116 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.World.Environment;
|
||||
import org.bukkit.WorldCreator;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.config.ConfigurationNode;
|
||||
import com.intellectualcrafters.plot.object.PlotGenerator;
|
||||
import com.intellectualcrafters.plot.object.PlotWorld;
|
||||
import com.intellectualcrafters.plot.object.SetupObject;
|
||||
import com.intellectualcrafters.plot.util.SetupUtils;
|
||||
|
||||
public class BukkitSetupUtils extends SetupUtils {
|
||||
|
||||
@Override
|
||||
public void updateGenerators() {
|
||||
if (SetupUtils.generators.size() > 0) {
|
||||
return;
|
||||
}
|
||||
final String testWorld = "CheckingPlotSquaredGenerator";
|
||||
for (final Plugin plugin : Bukkit.getPluginManager().getPlugins()) {
|
||||
if (plugin.isEnabled()) {
|
||||
final ChunkGenerator generator = plugin.getDefaultWorldGenerator(testWorld, "");
|
||||
if (generator != null) {
|
||||
PS.get().removePlotWorld(testWorld);
|
||||
final String name = plugin.getDescription().getName();
|
||||
// final PlotGenerator pgen = (PlotGenerator) generator;
|
||||
// if (pgen.getPlotManager() instanceof SquarePlotManager) {
|
||||
SetupUtils.generators.put(name, generator);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String setupWorld(final SetupObject object) {
|
||||
SetupUtils.manager.updateGenerators();
|
||||
final ConfigurationNode[] steps = object.step;
|
||||
final String world = object.world;
|
||||
for (final ConfigurationNode step : steps) {
|
||||
PS.get().config.set("worlds." + world + "." + step.getConstant(), step.getValue());
|
||||
}
|
||||
if (object.type != 0) {
|
||||
PS.get().config.set("worlds." + world + "." + "generator.type", object.type);
|
||||
PS.get().config.set("worlds." + world + "." + "generator.terrain", object.terrain);
|
||||
PS.get().config.set("worlds." + world + "." + "generator.plugin", object.plotManager);
|
||||
if (object.setupGenerator != null && !object.setupGenerator.equals(object.plotManager)) {
|
||||
PS.get().config.set("worlds." + world + "." + "generator.init", object.setupGenerator);
|
||||
}
|
||||
ChunkGenerator gen = generators.get(object.setupGenerator);
|
||||
if (gen instanceof PlotGenerator) {
|
||||
object.setupGenerator = null;
|
||||
}
|
||||
}
|
||||
try {
|
||||
PS.get().config.save(PS.get().configFile);
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (object.setupGenerator != null) {
|
||||
if ((Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null) && Bukkit.getPluginManager().getPlugin("Multiverse-Core").isEnabled()) {
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mv create " + world + " normal -g " + object.setupGenerator);
|
||||
} else {
|
||||
if ((Bukkit.getPluginManager().getPlugin("MultiWorld") != null) && Bukkit.getPluginManager().getPlugin("MultiWorld").isEnabled()) {
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mw create " + world + " plugin:" + object.setupGenerator);
|
||||
} else {
|
||||
final WorldCreator wc = new WorldCreator(object.world);
|
||||
wc.generator(object.setupGenerator);
|
||||
wc.environment(Environment.NORMAL);
|
||||
Bukkit.createWorld(wc);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ((Bukkit.getPluginManager().getPlugin("Multiverse-Core") != null) && Bukkit.getPluginManager().getPlugin("Multiverse-Core").isEnabled()) {
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mv create " + world + " normal");
|
||||
} else {
|
||||
if ((Bukkit.getPluginManager().getPlugin("MultiWorld") != null) && Bukkit.getPluginManager().getPlugin("MultiWorld").isEnabled()) {
|
||||
Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), "mw create " + world);
|
||||
} else {
|
||||
Bukkit.createWorld(new WorldCreator(object.world).environment(World.Environment.NORMAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
return object.world;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGenerator(PlotWorld plotworld) {
|
||||
if (SetupUtils.generators.size() == 0) {
|
||||
updateGenerators();
|
||||
}
|
||||
World world = Bukkit.getWorld(plotworld.worldname);
|
||||
if (world == null) {
|
||||
return null;
|
||||
}
|
||||
ChunkGenerator generator = world.getGenerator();
|
||||
if (!(generator instanceof PlotGenerator)) {
|
||||
return null;
|
||||
}
|
||||
for (Entry<String, ChunkGenerator> entry : generators.entrySet()) {
|
||||
if (entry.getValue().getClass().getName().equals(generator.getClass().getName())) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.intellectualcrafters.plot.BukkitMain;
|
||||
import com.intellectualcrafters.plot.util.TaskManager;
|
||||
|
||||
public class BukkitTaskManager extends TaskManager {
|
||||
@Override
|
||||
public int taskRepeat(final Runnable r, final int interval) {
|
||||
return BukkitMain.THIS.getServer().getScheduler().scheduleSyncRepeatingTask(BukkitMain.THIS, r, interval, interval);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskAsync(final Runnable r) {
|
||||
BukkitMain.THIS.getServer().getScheduler().runTaskAsynchronously(BukkitMain.THIS, r).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void task(final Runnable r) {
|
||||
BukkitMain.THIS.getServer().getScheduler().runTask(BukkitMain.THIS, r).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskLater(final Runnable r, final int delay) {
|
||||
BukkitMain.THIS.getServer().getScheduler().runTaskLater(BukkitMain.THIS, r, delay).getTaskId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void taskLaterAsync(final Runnable r, final int delay) {
|
||||
BukkitMain.THIS.getServer().getScheduler().runTaskLaterAsynchronously(BukkitMain.THIS, r, delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelTask(final int task) {
|
||||
if (task != -1) {
|
||||
Bukkit.getScheduler().cancelTask(task);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,389 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Biome;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.material.MaterialData;
|
||||
import org.bukkit.material.Sandstone;
|
||||
import org.bukkit.material.Step;
|
||||
import org.bukkit.material.Tree;
|
||||
import org.bukkit.material.WoodenStep;
|
||||
import org.bukkit.material.Wool;
|
||||
|
||||
import com.intellectualcrafters.plot.object.BukkitPlayer;
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.object.Location;
|
||||
import com.intellectualcrafters.plot.object.PlotBlock;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.schematic.PlotItem;
|
||||
import com.intellectualcrafters.plot.util.BlockManager;
|
||||
import com.intellectualcrafters.plot.util.ChunkManager;
|
||||
import com.intellectualcrafters.plot.util.StringComparison;
|
||||
|
||||
public class BukkitUtil extends BlockManager {
|
||||
private static HashMap<String, World> worlds = new HashMap<>();
|
||||
private static String lastString = null;
|
||||
private static World lastWorld = null;
|
||||
|
||||
private static Player lastPlayer = null;
|
||||
private static PlotPlayer lastPlotPlayer = null;
|
||||
|
||||
public static void removePlayer(final String plr) {
|
||||
lastPlayer = null;
|
||||
lastPlotPlayer = null;
|
||||
UUIDHandler.players.remove(plr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWorld(final String world) {
|
||||
return getWorld(world) != null;
|
||||
}
|
||||
|
||||
public static PlotPlayer getPlayer(final OfflinePlayer op) {
|
||||
if (op.isOnline()) {
|
||||
return getPlayer(op.getPlayer());
|
||||
}
|
||||
Player player = OfflinePlayerUtil.loadPlayer(op);
|
||||
player.loadData();
|
||||
return new BukkitPlayer(player);
|
||||
}
|
||||
|
||||
public static PlotPlayer getPlayer(final Player player) {
|
||||
if (player == lastPlayer) {
|
||||
return lastPlotPlayer;
|
||||
}
|
||||
String name = player.getName();
|
||||
PlotPlayer pp = UUIDHandler.players.get(name);
|
||||
if (pp != null) {
|
||||
return pp;
|
||||
}
|
||||
lastPlotPlayer = new BukkitPlayer(player);
|
||||
UUIDHandler.players.put(name, lastPlotPlayer);
|
||||
lastPlayer = player;
|
||||
return lastPlotPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBiome(final Location loc) {
|
||||
return getWorld(loc.getWorld()).getBiome(loc.getX(), loc.getZ()).name();
|
||||
}
|
||||
|
||||
public static Location getLocation(final org.bukkit.Location loc) {
|
||||
return new Location(loc.getWorld().getName(), (int) loc.getX(), (int) loc.getY(), (int) loc.getZ());
|
||||
}
|
||||
|
||||
public static org.bukkit.Location getLocation(final Location loc) {
|
||||
return new org.bukkit.Location(getWorld(loc.getWorld()), loc.getX(), loc.getY(), loc.getZ());
|
||||
}
|
||||
|
||||
public static World getWorld(final String string) {
|
||||
if (string == lastString) {
|
||||
return lastWorld;
|
||||
}
|
||||
World world = worlds.get(string);
|
||||
if (world == null) {
|
||||
world = Bukkit.getWorld(string);
|
||||
worlds.put(string, world);
|
||||
}
|
||||
return world;
|
||||
}
|
||||
|
||||
public static int getMaxHeight(final String world) {
|
||||
return getWorld(world).getMaxHeight();
|
||||
}
|
||||
|
||||
public static int getHeighestBlock(final String world, final int x, final int z) {
|
||||
return getWorld(world).getHighestBlockYAt(x, z);
|
||||
}
|
||||
|
||||
public static Chunk getChunkAt(final String worldname, final int x, final int z) {
|
||||
final World world = getWorld(worldname);
|
||||
return world.getChunkAt(x, z);
|
||||
}
|
||||
|
||||
// public static void update(final String world, final int x, final int z) {
|
||||
// final ArrayList<Chunk> chunks = new ArrayList<>();
|
||||
// final int distance = Bukkit.getViewDistance();
|
||||
// for (int cx = -distance; cx < distance; cx++) {
|
||||
// for (int cz = -distance; cz < distance; cz++) {
|
||||
// final Chunk chunk = getChunkAt(world, (x >> 4) + cx, (z >> 4) + cz);
|
||||
// chunks.add(chunk);
|
||||
// }
|
||||
// }
|
||||
// BukkitSetBlockManager.setBlockManager.update(chunks);
|
||||
// }
|
||||
|
||||
public static String getWorld(final Entity entity) {
|
||||
return entity.getWorld().getName();
|
||||
}
|
||||
|
||||
public static void teleportPlayer(final Player player, final Location loc) {
|
||||
final org.bukkit.Location bukkitLoc = new org.bukkit.Location(getWorld(loc.getWorld()), loc.getX(), loc.getY(), loc.getZ());
|
||||
player.teleport(bukkitLoc);
|
||||
}
|
||||
|
||||
public static List<Entity> getEntities(final String worldname) {
|
||||
return getWorld(worldname).getEntities();
|
||||
}
|
||||
|
||||
public static void setBlock(final World world, final int x, final int y, final int z, final int id, final byte data) {
|
||||
try {
|
||||
BukkitSetBlockManager.setBlockManager.set(world, x, y, z, id, data);
|
||||
} catch (final Throwable e) {
|
||||
BukkitSetBlockManager.setBlockManager = new SetBlockSlow();
|
||||
BukkitSetBlockManager.setBlockManager.set(world, x, y, z, id, data);
|
||||
}
|
||||
}
|
||||
|
||||
public static void setBiome(final String worldname, final int pos1_x, final int pos1_z, final int pos2_x, final int pos2_z, final String biome) {
|
||||
final Biome b = Biome.valueOf(biome.toUpperCase());
|
||||
final World world = getWorld(worldname);
|
||||
for (int x = pos1_x; x <= pos2_x; x++) {
|
||||
for (int z = pos1_z; z <= pos2_z; z++) {
|
||||
final Block blk = world.getBlockAt(x, 0, z);
|
||||
final Biome c = blk.getBiome();
|
||||
if (c.equals(b)) {
|
||||
x += 15;
|
||||
continue;
|
||||
}
|
||||
blk.setBiome(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void refreshChunk(final String name, final int x, final int z) {
|
||||
World world = getWorld(name);
|
||||
world.refreshChunk(x, z);
|
||||
world.loadChunk(x, z);
|
||||
}
|
||||
|
||||
public static void regenerateChunk(final String world, final int x, final int z) {
|
||||
World worldObj = getWorld(world);
|
||||
Chunk chunk = worldObj.getChunkAt(x, z);
|
||||
if (chunk.isLoaded() || chunk.load(false)) {
|
||||
ChunkManager.manager.regenerateChunk(world, new ChunkLoc(x, z));
|
||||
}
|
||||
}
|
||||
|
||||
public static PlotBlock getBlock(final Location loc) {
|
||||
final World world = getWorld(loc.getWorld());
|
||||
final Block block = world.getBlockAt(loc.getX(), loc.getY(), loc.getZ());
|
||||
if (block == null) {
|
||||
return new PlotBlock((short) 0, (byte) 0);
|
||||
}
|
||||
return new PlotBlock((short) block.getTypeId(), block.getData());
|
||||
}
|
||||
|
||||
public static Location getLocation(final Entity entity) {
|
||||
final org.bukkit.Location loc = entity.getLocation();
|
||||
final String world = loc.getWorld().getName();
|
||||
return new Location(world, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ());
|
||||
}
|
||||
|
||||
public static Location getLocationFull(final Entity entity) {
|
||||
final org.bukkit.Location loc = entity.getLocation();
|
||||
final String world = loc.getWorld().getName();
|
||||
return new Location(world, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), loc.getYaw(), loc.getPitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void functionSetBlocks(final String worldname, final int[] x, final int[] y, final int[] z, final int[] id, final byte[] data) {
|
||||
final World world = getWorld(worldname);
|
||||
for (int i = 0; i < x.length; i++) {
|
||||
BukkitUtil.setBlock(world, x[i], y[i], z[i], id[i], data[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void functionSetSign(final String worldname, final int x, final int y, final int z, final String[] lines) {
|
||||
final World world = getWorld(worldname);
|
||||
final Block block = world.getBlockAt(x, y, z);
|
||||
block.setType(Material.AIR);
|
||||
block.setTypeIdAndData(Material.WALL_SIGN.getId(), (byte) 2, false);
|
||||
final BlockState blockstate = block.getState();
|
||||
if ((blockstate instanceof Sign)) {
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
((Sign) blockstate).setLine(i, lines[i]);
|
||||
}
|
||||
((Sign) blockstate).update(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getViewDistance() {
|
||||
return Bukkit.getViewDistance();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void functionSetBiomes(final String worldname, final int[] x, final int[] z, final int[] biome) {
|
||||
final World world = getWorld(worldname);
|
||||
final Biome[] biomes = Biome.values();
|
||||
for (int i = 0; i < x.length; i++) {
|
||||
world.setBiome(x[i], z[i], biomes[biome[i]]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void functionSetBlock(final String worldname, final int x, final int y, final int z, final int id, final byte data) {
|
||||
BukkitUtil.setBlock(getWorld(worldname), x, y, z, id, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getSign(final Location loc) {
|
||||
final Block block = getWorld(loc.getWorld()).getBlockAt(loc.getX(), loc.getY(), loc.getZ());
|
||||
if (block != null) {
|
||||
if (block.getState() instanceof Sign) {
|
||||
final Sign sign = (Sign) block.getState();
|
||||
return sign.getLines();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getSpawn(final String world) {
|
||||
final org.bukkit.Location temp = getWorld(world).getSpawnLocation();
|
||||
return new Location(world, temp.getBlockX(), temp.getBlockY(), temp.getBlockZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeighestBlock(final Location loc) {
|
||||
return getWorld(loc.getWorld()).getHighestBlockAt(loc.getX(), loc.getZ()).getY();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBiomeFromString(final String biomeStr) {
|
||||
try {
|
||||
final Biome biome = Biome.valueOf(biomeStr.toUpperCase());
|
||||
if (biome == null) {
|
||||
return -1;
|
||||
}
|
||||
return Arrays.asList(Biome.values()).indexOf(biome);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getBiomeList() {
|
||||
final Biome[] biomes = Biome.values();
|
||||
final String[] list = new String[biomes.length];
|
||||
for (int i = 0; i < biomes.length; i++) {
|
||||
list[i] = biomes[i].name();
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockIdFromString(final String block) {
|
||||
final Material material = Material.valueOf(block.toUpperCase());
|
||||
if (material == null) {
|
||||
return -1;
|
||||
}
|
||||
return material.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addItems(String worldname, PlotItem items) {
|
||||
World world = getWorld(worldname);
|
||||
Block block = world.getBlockAt(items.x, items.y, items.z);
|
||||
if (block == null) {
|
||||
return false;
|
||||
}
|
||||
BlockState state = block.getState();
|
||||
if (state != null && state instanceof InventoryHolder) {
|
||||
InventoryHolder holder = ((InventoryHolder) state);
|
||||
Inventory inv = holder.getInventory();
|
||||
for (int i = 0; i < items.id.length; i++) {
|
||||
ItemStack item = new ItemStack(items.id[i], items.amount[i], items.data[i]);
|
||||
inv.addItem(item);
|
||||
}
|
||||
state.update(true);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBlockSolid(PlotBlock block) {
|
||||
try {
|
||||
Material material = Material.getMaterial(block.id);
|
||||
if (material.isBlock() && material.isSolid() && !material.hasGravity()) {
|
||||
Class<? extends MaterialData> data = material.getData();
|
||||
if ((data.equals(MaterialData.class) && !material.isTransparent() && material.isOccluding()) || data.equals(Tree.class) || data.equals(Sandstone.class) || data.equals(Wool.class) || data.equals(Step.class) || data.equals(WoodenStep.class)) {
|
||||
switch (material) {
|
||||
case NOTE_BLOCK:
|
||||
case MOB_SPAWNER: {
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getClosestMatchingName(PlotBlock block) {
|
||||
try {
|
||||
return Material.getMaterial(block.id).name();
|
||||
}
|
||||
catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringComparison<PlotBlock>.ComparisonResult getClosestBlock(String name) {
|
||||
try {
|
||||
double match;
|
||||
short id;
|
||||
byte data;
|
||||
String[] split = name.split(":");
|
||||
if (split.length == 2) {
|
||||
data = Byte.parseByte(split[1]);
|
||||
name = split[0];
|
||||
}
|
||||
else {
|
||||
data = 0;
|
||||
}
|
||||
if (StringUtils.isNumeric(split[0])) {
|
||||
id = Short.parseShort(split[0]);
|
||||
match = 0;
|
||||
}
|
||||
else {
|
||||
StringComparison<Material>.ComparisonResult comparison = new StringComparison<Material>(name, Material.values()).getBestMatchAdvanced();
|
||||
match = comparison.match;
|
||||
id = (short) comparison.best.getId();
|
||||
}
|
||||
PlotBlock block = new PlotBlock(id, data);
|
||||
StringComparison<PlotBlock> outer = new StringComparison<PlotBlock>();
|
||||
return outer.new ComparisonResult(match, block);
|
||||
|
||||
}
|
||||
catch (Exception e) {}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,713 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.net.Proxy;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.logging.Level;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import com.intellectualcrafters.configuration.InvalidConfigurationException;
|
||||
import com.intellectualcrafters.configuration.file.YamlConfiguration;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
|
||||
public class Metrics {
|
||||
/**
|
||||
* The current revision number
|
||||
*/
|
||||
private final static int REVISION = 7;
|
||||
/**
|
||||
* The base url of the metrics domain
|
||||
*/
|
||||
private static final String BASE_URL = "http://report.mcstats.org";
|
||||
/**
|
||||
* The url used to report a server's status
|
||||
*/
|
||||
private static final String REPORT_URL = "/plugin/%s";
|
||||
/**
|
||||
* Interval of time to ping (in minutes)
|
||||
*/
|
||||
private static final int PING_INTERVAL = 15;
|
||||
/**
|
||||
* The plugin this metrics submits for
|
||||
*/
|
||||
private final Plugin plugin;
|
||||
/**
|
||||
* All of the custom graphs to submit to metrics
|
||||
*/
|
||||
private final Set<Graph> graphs = Collections.synchronizedSet(new HashSet<Graph>());
|
||||
/**
|
||||
* The plugin configuration file
|
||||
*/
|
||||
private final YamlConfiguration configuration;
|
||||
/**
|
||||
* The plugin configuration file
|
||||
*/
|
||||
private final File configurationFile;
|
||||
/**
|
||||
* Unique server id
|
||||
*/
|
||||
private final String guid;
|
||||
/**
|
||||
* Debug mode
|
||||
*/
|
||||
private final boolean debug;
|
||||
/**
|
||||
* Lock for synchronization
|
||||
*/
|
||||
private final Object optOutLock = new Object();
|
||||
/**
|
||||
* The scheduled task
|
||||
*/
|
||||
private volatile BukkitTask task = null;
|
||||
|
||||
public Metrics(final Plugin plugin) throws IOException {
|
||||
if (plugin == null) {
|
||||
throw new IllegalArgumentException("Plugin cannot be null");
|
||||
}
|
||||
this.plugin = plugin;
|
||||
// load the config
|
||||
this.configurationFile = getConfigFile();
|
||||
this.configuration = YamlConfiguration.loadConfiguration(this.configurationFile);
|
||||
// add some defaults
|
||||
this.configuration.addDefault("opt-out", false);
|
||||
this.configuration.addDefault("guid", UUID.randomUUID().toString());
|
||||
this.configuration.addDefault("debug", false);
|
||||
// Do we need to create the file?
|
||||
if (this.configuration.get("guid", null) == null) {
|
||||
this.configuration.options().header("http://mcstats.org").copyDefaults(true);
|
||||
this.configuration.save(this.configurationFile);
|
||||
}
|
||||
// Load the guid then
|
||||
this.guid = this.configuration.getString("guid");
|
||||
this.debug = this.configuration.getBoolean("debug", false);
|
||||
}
|
||||
|
||||
/**
|
||||
* GZip compress a string of bytes
|
||||
*
|
||||
* @param input
|
||||
*
|
||||
* @return byte[] the file as a byte array
|
||||
*/
|
||||
public static byte[] gzip(final String input) {
|
||||
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
GZIPOutputStream gzos = null;
|
||||
try {
|
||||
gzos = new GZIPOutputStream(baos);
|
||||
gzos.write(input.getBytes("UTF-8"));
|
||||
} catch (final IOException e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (gzos != null) {
|
||||
try {
|
||||
gzos.close();
|
||||
} catch (final IOException ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a json encoded key/value pair to the given string builder.
|
||||
*
|
||||
* @param json
|
||||
* @param key
|
||||
* @param value
|
||||
*
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
private static void appendJSONPair(final StringBuilder json, final String key, final String value) throws UnsupportedEncodingException {
|
||||
boolean isValueNumeric = false;
|
||||
try {
|
||||
if (value.equals("0") || !value.endsWith("0")) {
|
||||
Double.parseDouble(value);
|
||||
isValueNumeric = true;
|
||||
}
|
||||
} catch (final NumberFormatException e) {
|
||||
isValueNumeric = false;
|
||||
}
|
||||
if (json.charAt(json.length() - 1) != '{') {
|
||||
json.append(',');
|
||||
}
|
||||
json.append(escapeJSON(key));
|
||||
json.append(':');
|
||||
if (isValueNumeric) {
|
||||
json.append(value);
|
||||
} else {
|
||||
json.append(escapeJSON(value));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape a string to create a valid JSON string
|
||||
*
|
||||
* @param text
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
private static String escapeJSON(final String text) {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append('"');
|
||||
for (int index = 0; index < text.length(); index++) {
|
||||
final char chr = text.charAt(index);
|
||||
switch (chr) {
|
||||
case '"':
|
||||
case '\\':
|
||||
builder.append('\\');
|
||||
builder.append(chr);
|
||||
break;
|
||||
case '\b':
|
||||
builder.append("\\b");
|
||||
break;
|
||||
case '\t':
|
||||
builder.append("\\t");
|
||||
break;
|
||||
case '\n':
|
||||
builder.append("\\n");
|
||||
break;
|
||||
case '\r':
|
||||
builder.append("\\r");
|
||||
break;
|
||||
default:
|
||||
if (chr < ' ') {
|
||||
final String t = "000" + Integer.toHexString(chr);
|
||||
builder.append("\\u" + t.substring(t.length() - 4));
|
||||
} else {
|
||||
builder.append(chr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
builder.append('"');
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode text as UTF-8
|
||||
*
|
||||
* @param text the text to encode
|
||||
*
|
||||
* @return the encoded text, as UTF-8
|
||||
*/
|
||||
private static String urlEncode(final String text) throws UnsupportedEncodingException {
|
||||
return URLEncoder.encode(text, "UTF-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct and create a Graph that can be used to separate specific plotters to their own graphs on the metrics
|
||||
* website. Plotters can be added to the graph object returned.
|
||||
*
|
||||
* @param name The name of the graph
|
||||
*
|
||||
* @return Graph object created. Will never return NULL under normal circumstances unless bad parameters are given
|
||||
*/
|
||||
public Graph createGraph(final String name) {
|
||||
if (name == null) {
|
||||
throw new IllegalArgumentException("Graph name cannot be null");
|
||||
}
|
||||
// Construct the graph object
|
||||
final Graph graph = new Graph(name);
|
||||
// Now we can add our graph
|
||||
this.graphs.add(graph);
|
||||
// and return back
|
||||
return graph;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a Graph object to BukkitMetrics that represents data for the plugin that should be sent to the backend
|
||||
*
|
||||
* @param graph The name of the graph
|
||||
*/
|
||||
public void addGraph(final Graph graph) {
|
||||
if (graph == null) {
|
||||
throw new IllegalArgumentException("Graph cannot be null");
|
||||
}
|
||||
this.graphs.add(graph);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start measuring statistics. This will immediately create an async repeating task as the plugin and send the
|
||||
* initial data to the metrics backend, and then after that it will post in increments of PING_INTERVAL * 1200
|
||||
* ticks.
|
||||
*
|
||||
* @return True if statistics measuring is running, otherwise false.
|
||||
*/
|
||||
public boolean start() {
|
||||
synchronized (this.optOutLock) {
|
||||
// Did we opt out?
|
||||
if (isOptOut()) {
|
||||
return false;
|
||||
}
|
||||
// Is metrics already running?
|
||||
if (this.task != null) {
|
||||
return true;
|
||||
}
|
||||
// Begin hitting the server with glorious data
|
||||
this.task = this.plugin.getServer().getScheduler().runTaskTimerAsynchronously(this.plugin, new Runnable() {
|
||||
private boolean firstPost = true;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
// This has to be synchronized or it can collide
|
||||
// with
|
||||
// the disable method.
|
||||
synchronized (Metrics.this.optOutLock) {
|
||||
// Disable Task, if it is running and the
|
||||
// server
|
||||
// owner decided to opt-out
|
||||
if (isOptOut() && (Metrics.this.task != null)) {
|
||||
Metrics.this.task.cancel();
|
||||
Metrics.this.task = null;
|
||||
// Tell all plotters to stop gathering
|
||||
// information.
|
||||
for (final Graph graph : Metrics.this.graphs) {
|
||||
graph.onOptOut();
|
||||
}
|
||||
}
|
||||
}
|
||||
// We use the inverse of firstPost because if it
|
||||
// is the
|
||||
// first time we are posting,
|
||||
// it is not a interval ping, so it evaluates to
|
||||
// FALSE
|
||||
// Each time thereafter it will evaluate to
|
||||
// TRUE, i.e
|
||||
// PING!
|
||||
postPlugin(!this.firstPost);
|
||||
// After the first post we set firstPost to
|
||||
// false
|
||||
// Each post thereafter will be a ping
|
||||
this.firstPost = false;
|
||||
} catch (final IOException e) {
|
||||
if (Metrics.this.debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, PING_INTERVAL * 1200);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Has the server owner denied plugin metrics?
|
||||
*
|
||||
* @return true if metrics should be opted out of it
|
||||
*/
|
||||
public boolean isOptOut() {
|
||||
synchronized (this.optOutLock) {
|
||||
try {
|
||||
// Reload the metrics file
|
||||
this.configuration.load(getConfigFile());
|
||||
} catch (final IOException ex) {
|
||||
if (this.debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
|
||||
}
|
||||
return true;
|
||||
} catch (final InvalidConfigurationException ex) {
|
||||
if (this.debug) {
|
||||
Bukkit.getLogger().log(Level.INFO, "[Metrics] " + ex.getMessage());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return this.configuration.getBoolean("opt-out", false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables metrics for the server by setting "opt-out" to false in the config file and starting the metrics task.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public void enable() throws IOException {
|
||||
// This has to be synchronized or it can collide with the check in the
|
||||
// task.
|
||||
synchronized (this.optOutLock) {
|
||||
// Check if the server owner has already set opt-out, if not, set
|
||||
// it.
|
||||
if (isOptOut()) {
|
||||
this.configuration.set("opt-out", false);
|
||||
this.configuration.save(this.configurationFile);
|
||||
}
|
||||
// Enable Task, if it is not running
|
||||
if (this.task == null) {
|
||||
start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables metrics for the server by setting "opt-out" to true in the config file and canceling the metrics task.
|
||||
*
|
||||
* @throws java.io.IOException
|
||||
*/
|
||||
public void disable() throws IOException {
|
||||
// This has to be synchronized or it can collide with the check in the
|
||||
// task.
|
||||
synchronized (this.optOutLock) {
|
||||
// Check if the server owner has already set opt-out, if not, set
|
||||
// it.
|
||||
if (!isOptOut()) {
|
||||
this.configuration.set("opt-out", true);
|
||||
this.configuration.save(this.configurationFile);
|
||||
}
|
||||
// Disable Task, if it is running
|
||||
if (this.task != null) {
|
||||
this.task.cancel();
|
||||
this.task = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the File object of the config file that should be used to store data such as the GUID and opt-out status
|
||||
*
|
||||
* @return the File object for the config file
|
||||
*/
|
||||
public File getConfigFile() {
|
||||
// I believe the easiest way to get the base folder (e.g craftbukkit set
|
||||
// via -P) for plugins to use
|
||||
// is to abuse the plugin object we already have
|
||||
// plugin.getDataFolder() => base/plugins/PluginA/
|
||||
// pluginsFolder => base/plugins/
|
||||
// The base is not necessarily relative to the startup directory.
|
||||
final File pluginsFolder = this.plugin.getDataFolder().getParentFile();
|
||||
// return => base/plugins/PluginMetrics/config.yml
|
||||
return new File(new File(pluginsFolder, "PluginMetrics"), "config.yml");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic method that posts a plugin to the metrics website
|
||||
*/
|
||||
private void postPlugin(final boolean isPing) throws IOException {
|
||||
// Server software specific section
|
||||
final PluginDescriptionFile description = this.plugin.getDescription();
|
||||
final String pluginName = description.getName();
|
||||
final boolean onlineMode = Bukkit.getServer().getOnlineMode(); // TRUE
|
||||
// if
|
||||
// online
|
||||
// mode
|
||||
// is
|
||||
// enabled
|
||||
final String pluginVersion = description.getVersion();
|
||||
final String serverVersion = Bukkit.getVersion();
|
||||
int playersOnline = 0;
|
||||
try {
|
||||
if (Bukkit.class.getMethod("getOnlinePlayers", new Class<?>[0]).getReturnType() == Collection.class) {
|
||||
playersOnline = ((Collection<?>) Bukkit.class.getMethod("getOnlinePlayers", new Class<?>[0]).invoke(null, new Object[0])).size();
|
||||
} else {
|
||||
playersOnline = ((Player[]) Bukkit.class.getMethod("getOnlinePlayers", new Class<?>[0]).invoke(null, new Object[0])).length;
|
||||
}
|
||||
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException ex) {
|
||||
}
|
||||
// END server software specific section -- all code below does not use
|
||||
// any code outside of this class / Java
|
||||
// Construct the post data
|
||||
final StringBuilder json = new StringBuilder(1024);
|
||||
json.append('{');
|
||||
// The plugin's description file containg all of the plugin data such as
|
||||
// name, version, author, etc
|
||||
appendJSONPair(json, "guid", this.guid);
|
||||
appendJSONPair(json, "plugin_version", pluginVersion);
|
||||
appendJSONPair(json, "server_version", serverVersion);
|
||||
appendJSONPair(json, "players_online", Integer.toString(playersOnline));
|
||||
// New data as of R6
|
||||
final String osname = System.getProperty("os.name");
|
||||
String osarch = System.getProperty("os.arch");
|
||||
final String osversion = System.getProperty("os.version");
|
||||
final String java_version = System.getProperty("java.version");
|
||||
final int coreCount = Runtime.getRuntime().availableProcessors();
|
||||
// normalize os arch .. amd64 -> x86_64
|
||||
if (osarch.equals("amd64")) {
|
||||
osarch = "x86_64";
|
||||
}
|
||||
appendJSONPair(json, "osname", osname);
|
||||
appendJSONPair(json, "osarch", osarch);
|
||||
appendJSONPair(json, "osversion", osversion);
|
||||
appendJSONPair(json, "cores", Integer.toString(coreCount));
|
||||
appendJSONPair(json, "auth_mode", onlineMode ? "1" : "0");
|
||||
appendJSONPair(json, "java_version", java_version);
|
||||
// If we're pinging, append it
|
||||
if (isPing) {
|
||||
appendJSONPair(json, "ping", "1");
|
||||
}
|
||||
if (this.graphs.size() > 0) {
|
||||
synchronized (this.graphs) {
|
||||
json.append(',');
|
||||
json.append('"');
|
||||
json.append("graphs");
|
||||
json.append('"');
|
||||
json.append(':');
|
||||
json.append('{');
|
||||
boolean firstGraph = true;
|
||||
for (final Graph graph : this.graphs) {
|
||||
final StringBuilder graphJson = new StringBuilder();
|
||||
graphJson.append('{');
|
||||
for (final Plotter plotter : graph.getPlotters()) {
|
||||
appendJSONPair(graphJson, plotter.getColumnName(), Integer.toString(plotter.getValue()));
|
||||
}
|
||||
graphJson.append('}');
|
||||
if (!firstGraph) {
|
||||
json.append(',');
|
||||
}
|
||||
json.append(escapeJSON(graph.getName()));
|
||||
json.append(':');
|
||||
json.append(graphJson);
|
||||
firstGraph = false;
|
||||
}
|
||||
json.append('}');
|
||||
}
|
||||
}
|
||||
// close json
|
||||
json.append('}');
|
||||
// Create the url
|
||||
final URL url = new URL(BASE_URL + String.format(REPORT_URL, urlEncode(pluginName)));
|
||||
// Connect to the website
|
||||
URLConnection connection;
|
||||
// Mineshafter creates a socks proxy, so we can safely bypass it
|
||||
// It does not reroute POST requests so we need to go around it
|
||||
if (isMineshafterPresent()) {
|
||||
connection = url.openConnection(Proxy.NO_PROXY);
|
||||
} else {
|
||||
connection = url.openConnection();
|
||||
}
|
||||
final byte[] uncompressed = json.toString().getBytes();
|
||||
final byte[] compressed = gzip(json.toString());
|
||||
// Headers
|
||||
connection.addRequestProperty("User-Agent", "MCStats/" + REVISION);
|
||||
connection.addRequestProperty("Content-Type", "application/json");
|
||||
connection.addRequestProperty("Content-Encoding", "gzip");
|
||||
connection.addRequestProperty("Content-Length", Integer.toString(compressed.length));
|
||||
connection.addRequestProperty("Accept", "application/json");
|
||||
connection.addRequestProperty("Connection", "close");
|
||||
connection.setDoOutput(true);
|
||||
if (this.debug) {
|
||||
PS.log("[Metrics] Prepared request for " + pluginName + " uncompressed=" + uncompressed.length + " compressed=" + compressed.length);
|
||||
}
|
||||
// Write the data
|
||||
final OutputStream os = connection.getOutputStream();
|
||||
os.write(compressed);
|
||||
os.flush();
|
||||
// Now read the response
|
||||
final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
|
||||
String response = reader.readLine();
|
||||
// close resources
|
||||
os.close();
|
||||
reader.close();
|
||||
if ((response == null) || response.startsWith("ERR") || response.startsWith("7")) {
|
||||
if (response == null) {
|
||||
response = "null";
|
||||
} else if (response.startsWith("7")) {
|
||||
response = response.substring(response.startsWith("7,") ? 2 : 1);
|
||||
}
|
||||
throw new IOException(response);
|
||||
} else {
|
||||
// Is this the first update this hour?
|
||||
if (response.equals("1") || response.contains("This is your first update this hour")) {
|
||||
synchronized (this.graphs) {
|
||||
for (final Graph graph : this.graphs) {
|
||||
for (final Plotter plotter : graph.getPlotters()) {
|
||||
plotter.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if mineshafter is present. If it is, we need to bypass it to send POST requests
|
||||
*
|
||||
* @return true if mineshafter is installed on the server
|
||||
*/
|
||||
private boolean isMineshafterPresent() {
|
||||
try {
|
||||
Class.forName("mineshafter.MineServer");
|
||||
return true;
|
||||
} catch (final Exception e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a custom graph on the website
|
||||
*/
|
||||
public static class Graph {
|
||||
/**
|
||||
* The graph's name, alphanumeric and spaces only :) If it does not comply to the above when submitted, it is
|
||||
* rejected
|
||||
*/
|
||||
private final String name;
|
||||
/**
|
||||
* The set of plotters that are contained within this graph
|
||||
*/
|
||||
private final Set<Plotter> plotters = new LinkedHashSet<Plotter>();
|
||||
|
||||
private Graph(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the graph's name
|
||||
*
|
||||
* @return the Graph's name
|
||||
*/
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a plotter to the graph, which will be used to plot entries
|
||||
*
|
||||
* @param plotter the plotter to add to the graph
|
||||
*/
|
||||
public void addPlotter(final Plotter plotter) {
|
||||
this.plotters.add(plotter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a plotter from the graph
|
||||
*
|
||||
* @param plotter the plotter to remove from the graph
|
||||
*/
|
||||
public void removePlotter(final Plotter plotter) {
|
||||
this.plotters.remove(plotter);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an <b>unmodifiable</b> set of the plotter objects in the graph
|
||||
*
|
||||
* @return an unmodifiable {@link java.util.Set} of the plotter objects
|
||||
*/
|
||||
public Set<Plotter> getPlotters() {
|
||||
return Collections.unmodifiableSet(this.plotters);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return this.name.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if (!(object instanceof Graph)) {
|
||||
return false;
|
||||
}
|
||||
final Graph graph = (Graph) object;
|
||||
return graph.name.equals(this.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the server owner decides to opt-out of BukkitMetrics while the server is running.
|
||||
*/
|
||||
protected void onOptOut() {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface used to collect custom data for a plugin
|
||||
*/
|
||||
public static abstract class Plotter {
|
||||
/**
|
||||
* The plot's name
|
||||
*/
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Construct a plotter with the default plot name
|
||||
*/
|
||||
public Plotter() {
|
||||
this("Default");
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a plotter with a specific plot name
|
||||
*
|
||||
* @param name the name of the plotter to use, which will show up on the website
|
||||
*/
|
||||
public Plotter(final String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current value for the plotted point. Since this function defers to an external function it may or may
|
||||
* not return immediately thus cannot be guaranteed to be thread friendly or safe. This function can be called
|
||||
* from any thread so care should be taken when accessing resources that need to be synchronized.
|
||||
*
|
||||
* @return the current value for the point to be plotted.
|
||||
*/
|
||||
public abstract int getValue();
|
||||
|
||||
/**
|
||||
* Get the column name for the plotted point
|
||||
*
|
||||
* @return the plotted point's column name
|
||||
*/
|
||||
public String getColumnName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called after the website graphs have been updated
|
||||
*/
|
||||
public void reset() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return getColumnName().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object object) {
|
||||
if (!(object instanceof Plotter)) {
|
||||
return false;
|
||||
}
|
||||
final Plotter plotter = (Plotter) object;
|
||||
return plotter.name.equals(this.name) && (plotter.getValue() == getValue());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,92 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.callConstructor;
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.callMethod;
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.getCbClass;
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.getNmsClass;
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.getUtilClass;
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.makeConstructor;
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.makeMethod;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class OfflinePlayerUtil {
|
||||
|
||||
public static Player loadPlayer(final String name) {
|
||||
return loadPlayer(Bukkit.getOfflinePlayer(name));
|
||||
}
|
||||
|
||||
public static Player loadPlayer(final UUID id) {
|
||||
return loadPlayer(Bukkit.getOfflinePlayer(id));
|
||||
}
|
||||
|
||||
public static Player loadPlayer(final OfflinePlayer player) {
|
||||
if (player == null) {
|
||||
return null;
|
||||
}
|
||||
if (player instanceof Player) {
|
||||
return (Player) player;
|
||||
}
|
||||
return loadPlayer(player.getUniqueId(), player.getName());
|
||||
}
|
||||
|
||||
private static Player loadPlayer(final UUID id, final String name) {
|
||||
final Object server = getMinecraftServer();
|
||||
final Object interactManager = newPlayerInteractManager();
|
||||
final Object worldServer = getWorldServer();
|
||||
final Object profile = newGameProfile(id, name);
|
||||
final Class<?> entityPlayerClass = getNmsClass("EntityPlayer");
|
||||
final Constructor entityPlayerConstructor = makeConstructor(entityPlayerClass, getNmsClass("MinecraftServer"), getNmsClass("WorldServer"), getUtilClass("com.mojang.authlib.GameProfile"), getNmsClass("PlayerInteractManager"));
|
||||
final Object entityPlayer = callConstructor(entityPlayerConstructor, server, worldServer, profile, interactManager);
|
||||
final Player player = (Player) getBukkitEntity(entityPlayer);
|
||||
return player;
|
||||
}
|
||||
|
||||
private static Object newGameProfile(final UUID id, final String name) {
|
||||
final Class<?> gameProfileClass = getUtilClass("com.mojang.authlib.GameProfile");
|
||||
if (gameProfileClass == null) { //Before uuids
|
||||
return name;
|
||||
}
|
||||
Constructor gameProfileConstructor = null;
|
||||
gameProfileConstructor = makeConstructor(gameProfileClass, UUID.class, String.class);
|
||||
if (gameProfileConstructor == null) { //Verson has string constructor
|
||||
gameProfileConstructor = makeConstructor(gameProfileClass, String.class, String.class);
|
||||
return callConstructor(gameProfileConstructor, id.toString(), name);
|
||||
} else { //Version has uuid constructor
|
||||
return callConstructor(gameProfileConstructor, id, name);
|
||||
}
|
||||
}
|
||||
|
||||
private static Object newPlayerInteractManager() {
|
||||
final Object worldServer = getWorldServer();
|
||||
final Class<?> playerInteractClass = getNmsClass("PlayerInteractManager");
|
||||
final Class<?> worldClass = getNmsClass("World");
|
||||
final Constructor c = makeConstructor(playerInteractClass, worldClass);
|
||||
return callConstructor(c, worldServer);
|
||||
}
|
||||
|
||||
private static Object getWorldServer() {
|
||||
final Object server = getMinecraftServer();
|
||||
final Class<?> minecraftServerClass = getNmsClass("MinecraftServer");
|
||||
final Method getWorldServer = makeMethod(minecraftServerClass, "getWorldServer", int.class);
|
||||
return callMethod(getWorldServer, server, 0);
|
||||
}
|
||||
|
||||
//NMS Utils
|
||||
|
||||
private static Object getMinecraftServer() {
|
||||
return callMethod(makeMethod(getCbClass("CraftServer"), "getServer"), Bukkit.getServer());
|
||||
}
|
||||
|
||||
private static Entity getBukkitEntity(final Object o) {
|
||||
final Method getBukkitEntity = makeMethod(o.getClass(), "getBukkitEntity");
|
||||
return callMethod(getBukkitEntity, o);
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefConstructor;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefField;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
|
||||
|
||||
/**
|
||||
* An utility that can be used to send chunks, rather than using bukkit code to do so (uses heavy NMS)
|
||||
*
|
||||
* @author Empire92
|
||||
*/
|
||||
public class SendChunk {
|
||||
|
||||
// Ref Class
|
||||
private static final RefClass classWorld = getRefClass("{nms}.World");
|
||||
private static final RefClass classEntityPlayer = getRefClass("{nms}.EntityPlayer");
|
||||
private static final RefClass classChunkCoordIntPair = getRefClass("{nms}.ChunkCoordIntPair");
|
||||
private static final RefClass classCraftChunk = getRefClass("{cb}.CraftChunk");
|
||||
private static final RefClass classChunk = getRefClass("{nms}.Chunk");
|
||||
private static boolean v1_7_10 = PS.get().IMP.checkVersion(1, 7, 10) && !PS.get().IMP.checkVersion(1, 8, 0);
|
||||
// Ref Method
|
||||
private static RefMethod methodGetHandle;
|
||||
// Ref Field
|
||||
private static RefField chunkCoordIntPairQueue;
|
||||
private static RefField players;
|
||||
private static RefField locX;
|
||||
private static RefField locZ;
|
||||
private static RefField world;
|
||||
// Ref Constructor
|
||||
private static RefConstructor ChunkCoordIntPairCon;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public SendChunk() throws NoSuchMethodException {
|
||||
methodGetHandle = classCraftChunk.getMethod("getHandle");
|
||||
chunkCoordIntPairQueue = classEntityPlayer.getField("chunkCoordIntPairQueue");
|
||||
players = classWorld.getField("players");
|
||||
locX = classEntityPlayer.getField("locX");
|
||||
locZ = classEntityPlayer.getField("locZ");
|
||||
world = classChunk.getField("world");
|
||||
ChunkCoordIntPairCon = classChunkCoordIntPair.getConstructor(int.class, int.class);
|
||||
}
|
||||
|
||||
public static void sendChunk(final Collection<Chunk> chunks) {
|
||||
int diffx, diffz;
|
||||
final int view = Bukkit.getServer().getViewDistance() << 4;
|
||||
for (final Chunk chunk : chunks) {
|
||||
if (!chunk.isLoaded()) {
|
||||
continue;
|
||||
}
|
||||
boolean unload = true;
|
||||
final Object c = methodGetHandle.of(chunk).call();
|
||||
final Object w = world.of(c).get();
|
||||
final Object p = players.of(w).get();
|
||||
for (final Object ep : (List<Object>) p) {
|
||||
final int x = ((Double) locX.of(ep).get()).intValue();
|
||||
final int z = ((Double) locZ.of(ep).get()).intValue();
|
||||
diffx = Math.abs(x - (chunk.getX() << 4));
|
||||
diffz = Math.abs(z - (chunk.getZ() << 4));
|
||||
if ((diffx <= view) && (diffz <= view)) {
|
||||
unload = false;
|
||||
if (v1_7_10) {
|
||||
chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ());
|
||||
chunk.load(true);
|
||||
}
|
||||
else {
|
||||
final Object pair = ChunkCoordIntPairCon.create(chunk.getX(), chunk.getZ());
|
||||
final Object pq = chunkCoordIntPairQueue.of(ep).get();
|
||||
((List) pq).add(pair);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unload) {
|
||||
chunk.unload(true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendChunk(final String worldname, final List<ChunkLoc> locs) {
|
||||
final World myworld = Bukkit.getWorld(worldname);
|
||||
final ArrayList<Chunk> chunks = new ArrayList<>();
|
||||
for (final ChunkLoc loc : locs) {
|
||||
chunks.add(myworld.getChunkAt(loc.x, loc.z));
|
||||
}
|
||||
sendChunk(chunks);
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
|
||||
import com.intellectualcrafters.plot.util.TaskManager;
|
||||
|
||||
/**
|
||||
* SetBlockFast class<br> Used to do fast world editing
|
||||
*
|
||||
* @author Empire92
|
||||
*/
|
||||
public class SetBlockFast extends BukkitSetBlockManager {
|
||||
private static final RefClass classBlock = getRefClass("{nms}.Block");
|
||||
private static final RefClass classChunk = getRefClass("{nms}.Chunk");
|
||||
private static final RefClass classWorld = getRefClass("{nms}.World");
|
||||
private static final RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
|
||||
private static RefMethod methodGetHandle;
|
||||
private static RefMethod methodGetChunkAt;
|
||||
private static RefMethod methodA;
|
||||
private static RefMethod methodGetById;
|
||||
|
||||
public static HashMap<ChunkLoc, Chunk> toUpdate = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public SetBlockFast() throws NoSuchMethodException {
|
||||
methodGetHandle = classCraftWorld.getMethod("getHandle");
|
||||
methodGetChunkAt = classWorld.getMethod("getChunkAt", int.class, int.class);
|
||||
methodA = classChunk.getMethod("a", int.class, int.class, int.class, classBlock, int.class);
|
||||
methodGetById = classBlock.getMethod("getById", int.class);
|
||||
TaskManager.runTaskRepeat(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
// TODO Auto-generated method stub
|
||||
update(toUpdate.values());
|
||||
toUpdate = new HashMap<>();
|
||||
}
|
||||
}, 20);
|
||||
}
|
||||
|
||||
private ChunkLoc lastLoc = null;
|
||||
|
||||
/**
|
||||
* Set the block at the location
|
||||
*
|
||||
* @param world World in which the block should be set
|
||||
* @param x X Coordinate
|
||||
* @param y Y Coordinate
|
||||
* @param z Z Coordinate
|
||||
* @param blockId Block ID
|
||||
* @param data Block Data Value
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
public void set(final org.bukkit.World world, final int x, final int y, final int z, final int blockId, final byte data) {
|
||||
if (blockId == -1) {
|
||||
world.getBlockAt(x, y, z).setData(data, false);
|
||||
return;
|
||||
}
|
||||
int X = x >> 4;
|
||||
int Z = z >> 4;
|
||||
ChunkLoc loc = new ChunkLoc(X, Z);
|
||||
if (!loc.equals(lastLoc)) {
|
||||
Chunk chunk = toUpdate.get(loc);
|
||||
if (chunk == null) {
|
||||
chunk = world.getChunkAt(X, Z);
|
||||
toUpdate.put(loc, chunk);
|
||||
}
|
||||
chunk.load(false);
|
||||
}
|
||||
|
||||
final Object w = methodGetHandle.of(world).call();
|
||||
final Object chunk = methodGetChunkAt.of(w).call(x >> 4, z >> 4);
|
||||
final Object block = methodGetById.of(null).call(blockId);
|
||||
methodA.of(chunk).call(x & 0x0f, y, z & 0x0f, block, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update chunks
|
||||
*
|
||||
* @param chunks list of chunks to update
|
||||
*/
|
||||
@Override
|
||||
public void update(final Collection<Chunk> chunks) {
|
||||
if (chunks.size() == 0) {
|
||||
return;
|
||||
}
|
||||
if (!MainUtil.canSendChunk) {
|
||||
for (Chunk chunk : chunks) {
|
||||
chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ());
|
||||
chunk.unload(true, false);
|
||||
chunk.load();
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
SendChunk.sendChunk(chunks);
|
||||
} catch (final Throwable e) {
|
||||
MainUtil.canSendChunk = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,348 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// PlotSquared - A plot manager and world generator for the Bukkit API /
|
||||
// Copyright (c) 2014 IntellectualSites/IntellectualCrafters /
|
||||
// /
|
||||
// This program is free software; you can redistribute it and/or modify /
|
||||
// it under the terms of the GNU General Public License as published by /
|
||||
// the Free Software Foundation; either version 3 of the License, or /
|
||||
// (at your option) any later version. /
|
||||
// /
|
||||
// This program is distributed in the hope that it will be useful, /
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of /
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the /
|
||||
// GNU General Public License for more details. /
|
||||
// /
|
||||
// You should have received a copy of the GNU General Public License /
|
||||
// along with this program; if not, write to the Free Software Foundation, /
|
||||
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA /
|
||||
// /
|
||||
// You can contact us via: support@intellectualsites.com /
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import static com.intellectualcrafters.plot.util.ReflectionUtils.getRefClass;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import com.intellectualcrafters.plot.object.ChunkLoc;
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefClass;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefConstructor;
|
||||
import com.intellectualcrafters.plot.util.ReflectionUtils.RefMethod;
|
||||
import com.intellectualcrafters.plot.util.TaskManager;
|
||||
|
||||
/**
|
||||
* SetBlockFast class<br> Used to do fast world editing
|
||||
*
|
||||
* @author Empire92
|
||||
*/
|
||||
public class SetBlockFast_1_8 extends BukkitSetBlockManager {
|
||||
private static final RefClass classBlock = getRefClass("{nms}.Block");
|
||||
private static final RefClass classBlockPosition = getRefClass("{nms}.BlockPosition");
|
||||
private static final RefClass classIBlockData = getRefClass("{nms}.IBlockData");
|
||||
private static final RefClass classChunk = getRefClass("{nms}.Chunk");
|
||||
private static final RefClass classWorld = getRefClass("{nms}.World");
|
||||
private static final RefClass classCraftWorld = getRefClass("{cb}.CraftWorld");
|
||||
private static RefMethod methodGetHandle;
|
||||
private static RefMethod methodGetChunkAt;
|
||||
private static RefMethod methodA;
|
||||
private static RefMethod methodGetByCombinedId;
|
||||
private static RefConstructor constructorBlockPosition;
|
||||
|
||||
public static HashMap<ChunkLoc, Chunk> toUpdate = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @throws NoSuchMethodException
|
||||
*/
|
||||
public SetBlockFast_1_8() throws NoSuchMethodException {
|
||||
constructorBlockPosition = classBlockPosition.getConstructor(int.class, int.class, int.class);
|
||||
methodGetByCombinedId = classBlock.getMethod("getByCombinedId", int.class);
|
||||
methodGetHandle = classCraftWorld.getMethod("getHandle");
|
||||
methodGetChunkAt = classWorld.getMethod("getChunkAt", int.class, int.class);
|
||||
methodA = classChunk.getMethod("a", classBlockPosition, classIBlockData);
|
||||
TaskManager.runTaskRepeat(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
int count = 0;
|
||||
ArrayList<Chunk> chunks = new ArrayList<Chunk>();
|
||||
Iterator<Entry<ChunkLoc, Chunk>> i = toUpdate.entrySet().iterator();
|
||||
while (i.hasNext() && count < 1024) {
|
||||
chunks.add(i.next().getValue());
|
||||
i.remove();
|
||||
count++;
|
||||
}
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
update(chunks);
|
||||
}
|
||||
}, 20);
|
||||
}
|
||||
|
||||
private ChunkLoc lastLoc = null;
|
||||
|
||||
/**
|
||||
* Set the block at the location
|
||||
*
|
||||
* @param world World in which the block should be set
|
||||
* @param x X Coordinate
|
||||
* @param y Y Coordinate
|
||||
* @param z Z Coordinate
|
||||
* @param id Block ID
|
||||
* @param data Block Data Value
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void set(final World world, final int x, final int y, final int z, final int id, final byte data) {
|
||||
if (id == -1) {
|
||||
world.getBlockAt(x, y, z).setData(data, false);
|
||||
return;
|
||||
}
|
||||
// Start blockstate workaround //
|
||||
switch (id) {
|
||||
case 54:
|
||||
case 130:
|
||||
case 142:
|
||||
case 27:
|
||||
case 137:
|
||||
case 52:
|
||||
case 154:
|
||||
case 84:
|
||||
case 25:
|
||||
case 144:
|
||||
case 138:
|
||||
case 176:
|
||||
case 177:
|
||||
case 63:
|
||||
case 68:
|
||||
case 323:
|
||||
case 117:
|
||||
case 116:
|
||||
case 28:
|
||||
case 66:
|
||||
case 157:
|
||||
case 61:
|
||||
case 62:
|
||||
case 140:
|
||||
case 146:
|
||||
case 149:
|
||||
case 150:
|
||||
case 158:
|
||||
case 23:
|
||||
case 123:
|
||||
case 124:
|
||||
case 29:
|
||||
case 33:
|
||||
case 151:
|
||||
case 178: {
|
||||
final Block block = world.getBlockAt(x, y, z);
|
||||
if (block.getData() == data) {
|
||||
if (block.getTypeId() != id) {
|
||||
block.setTypeId(id, false);
|
||||
}
|
||||
} else {
|
||||
if (block.getTypeId() == id) {
|
||||
block.setData(data, false);
|
||||
} else {
|
||||
block.setTypeIdAndData(id, data, false);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Start data value shortcut
|
||||
Block block = world.getBlockAt(x, y, z);
|
||||
int currentId = block.getTypeId();
|
||||
if (currentId == id) {
|
||||
switch(id) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 13:
|
||||
case 14:
|
||||
case 15:
|
||||
case 20:
|
||||
case 21:
|
||||
case 22:
|
||||
case 24:
|
||||
case 25:
|
||||
case 30:
|
||||
case 32:
|
||||
case 37:
|
||||
case 39:
|
||||
case 40:
|
||||
case 41:
|
||||
case 42:
|
||||
case 45:
|
||||
case 46:
|
||||
case 47:
|
||||
case 48:
|
||||
case 49:
|
||||
case 50:
|
||||
case 51:
|
||||
case 52:
|
||||
case 54:
|
||||
case 55:
|
||||
case 56:
|
||||
case 57:
|
||||
case 58:
|
||||
case 60:
|
||||
case 61:
|
||||
case 62:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 73:
|
||||
case 74:
|
||||
case 75:
|
||||
case 76:
|
||||
case 78:
|
||||
case 79:
|
||||
case 80:
|
||||
case 81:
|
||||
case 82:
|
||||
case 83:
|
||||
case 84:
|
||||
case 85:
|
||||
case 87:
|
||||
case 88:
|
||||
case 101:
|
||||
case 102:
|
||||
case 103:
|
||||
case 110:
|
||||
case 112:
|
||||
case 113:
|
||||
case 117:
|
||||
case 121:
|
||||
case 122:
|
||||
case 123:
|
||||
case 124:
|
||||
case 129:
|
||||
case 133:
|
||||
case 138:
|
||||
case 137:
|
||||
case 140:
|
||||
case 165:
|
||||
case 166:
|
||||
case 169:
|
||||
case 170:
|
||||
case 172:
|
||||
case 173:
|
||||
case 174:
|
||||
case 176:
|
||||
case 177:
|
||||
case 181:
|
||||
case 182:
|
||||
case 188:
|
||||
case 189:
|
||||
case 190:
|
||||
case 191:
|
||||
case 192: {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (block.getData() == data) {
|
||||
return;
|
||||
}
|
||||
block.setData(data);
|
||||
return;
|
||||
}
|
||||
switch(currentId) {
|
||||
case 54:
|
||||
case 130:
|
||||
case 142:
|
||||
case 27:
|
||||
case 137:
|
||||
case 52:
|
||||
case 154:
|
||||
case 84:
|
||||
case 25:
|
||||
case 144:
|
||||
case 138:
|
||||
case 176:
|
||||
case 177:
|
||||
case 63:
|
||||
case 68:
|
||||
case 323:
|
||||
case 117:
|
||||
case 116:
|
||||
case 28:
|
||||
case 66:
|
||||
case 157:
|
||||
case 61:
|
||||
case 62:
|
||||
case 140:
|
||||
case 146:
|
||||
case 149:
|
||||
case 150:
|
||||
case 158:
|
||||
case 23:
|
||||
case 123:
|
||||
case 124:
|
||||
case 29:
|
||||
case 33:
|
||||
case 151:
|
||||
case 178: {
|
||||
if (block.getData() == data) {
|
||||
block.setTypeId(id, false);
|
||||
} else {
|
||||
block.setTypeIdAndData(id, data, false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
// End blockstate workaround //
|
||||
|
||||
int X = x >> 4;
|
||||
int Z = z >> 4;
|
||||
ChunkLoc loc = new ChunkLoc(X, Z);
|
||||
if (!loc.equals(lastLoc)) {
|
||||
Chunk chunk = toUpdate.get(loc);
|
||||
if (chunk == null) {
|
||||
chunk = world.getChunkAt(X, Z);
|
||||
toUpdate.put(loc, chunk);
|
||||
}
|
||||
chunk.load(false);
|
||||
}
|
||||
// check sign
|
||||
final Object w = methodGetHandle.of(world).call();
|
||||
final Object chunk = methodGetChunkAt.of(w).call(x >> 4, z >> 4);
|
||||
final Object pos = constructorBlockPosition.create(x & 0x0f, y, z & 0x0f);
|
||||
final Object combined = methodGetByCombinedId.of(null).call(id + (data << 12));
|
||||
methodA.of(chunk).call(pos, combined);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final Collection<Chunk> chunks) {
|
||||
if (chunks.size() == 0) {
|
||||
return;
|
||||
}
|
||||
if (!MainUtil.canSendChunk) {
|
||||
for (Chunk chunk : chunks) {
|
||||
chunk.getWorld().refreshChunk(chunk.getX(), chunk.getZ());
|
||||
chunk.unload(true, false);
|
||||
chunk.load();
|
||||
}
|
||||
return;
|
||||
}
|
||||
try {
|
||||
SendChunk.sendChunk(chunks);
|
||||
} catch (final Throwable e) {
|
||||
MainUtil.canSendChunk = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
|
||||
import com.intellectualcrafters.plot.util.MainUtil;
|
||||
|
||||
public class SetBlockSlow extends BukkitSetBlockManager {
|
||||
@Override
|
||||
public void set(final World world, final int x, final int y, final int z, final int id, final byte data) {
|
||||
final Block block = world.getBlockAt(x, y, z);
|
||||
if (id == -1) {
|
||||
block.setData(data, false);
|
||||
return;
|
||||
}
|
||||
if (block.getData() == data) {
|
||||
if (block.getTypeId() != id) {
|
||||
block.setTypeId(id, false);
|
||||
}
|
||||
} else {
|
||||
if (block.getTypeId() == id) {
|
||||
block.setData(data, false);
|
||||
} else {
|
||||
block.setTypeIdAndData(id, data, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(final Collection<Chunk> chunks) {
|
||||
if (MainUtil.canSendChunk) {
|
||||
try {
|
||||
SendChunk.sendChunk(chunks);
|
||||
} catch (final Throwable e) {
|
||||
MainUtil.canSendChunk = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (Chunk chunk : chunks) {
|
||||
chunk.unload();
|
||||
chunk.load(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.generator.BlockPopulator;
|
||||
import org.bukkit.generator.ChunkGenerator;
|
||||
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.generator.AugmentedPopulator;
|
||||
import com.intellectualcrafters.plot.util.SetupUtils;
|
||||
|
||||
public class SetGenCB {
|
||||
public static void setGenerator(World world) throws Exception {
|
||||
SetupUtils.manager.updateGenerators();
|
||||
PS.get().removePlotWorldAbs(world.getName());
|
||||
ChunkGenerator gen = world.getGenerator();
|
||||
if (gen == null) {
|
||||
return;
|
||||
}
|
||||
String name = gen.getClass().getCanonicalName();
|
||||
boolean set = false;
|
||||
for (ChunkGenerator newGen : SetupUtils.generators.values()) {
|
||||
if (newGen.getClass().getCanonicalName().equals(name)) {
|
||||
// set generator
|
||||
Field generator = world.getClass().getDeclaredField("generator");
|
||||
Field populators = world.getClass().getDeclaredField("populators");
|
||||
generator.setAccessible(true);
|
||||
populators.setAccessible(true);
|
||||
// Set populators (just in case)
|
||||
populators.set(world, new ArrayList<>());
|
||||
// Set generator
|
||||
Constructor<? extends ChunkGenerator> constructor = newGen.getClass().getConstructor(String.class);
|
||||
ChunkGenerator newNewGen = constructor.newInstance(world.getName());
|
||||
generator.set(world, newNewGen);
|
||||
populators.set(world, newNewGen.getDefaultPopulators(world));
|
||||
// end
|
||||
set = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!set) {
|
||||
Iterator<BlockPopulator> iter = world.getPopulators().iterator();
|
||||
while (iter.hasNext()) {
|
||||
if (iter.next() instanceof AugmentedPopulator) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
PS.get().loadWorld(world.getName(), null);
|
||||
}
|
||||
}
|
@ -0,0 +1,319 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.HashBiMap;
|
||||
import com.google.common.io.Files;
|
||||
import com.google.common.io.InputSupplier;
|
||||
import com.intellectualcrafters.plot.PS;
|
||||
import com.intellectualcrafters.plot.config.C;
|
||||
import com.intellectualcrafters.plot.config.Settings;
|
||||
import com.intellectualcrafters.plot.database.DBFunc;
|
||||
import com.intellectualcrafters.plot.object.BukkitOfflinePlayer;
|
||||
import com.intellectualcrafters.plot.object.OfflinePlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.Plot;
|
||||
import com.intellectualcrafters.plot.object.PlotPlayer;
|
||||
import com.intellectualcrafters.plot.object.StringWrapper;
|
||||
import com.intellectualcrafters.plot.util.ExpireManager;
|
||||
import com.intellectualcrafters.plot.util.NbtFactory;
|
||||
import com.intellectualcrafters.plot.util.NbtFactory.NbtCompound;
|
||||
import com.intellectualcrafters.plot.util.NbtFactory.StreamOptions;
|
||||
import com.intellectualcrafters.plot.util.TaskManager;
|
||||
import com.intellectualcrafters.plot.uuid.OfflineUUIDWrapper;
|
||||
import com.intellectualcrafters.plot.uuid.UUIDWrapper;
|
||||
|
||||
public class UUIDHandler {
|
||||
/**
|
||||
* Map containing names and UUIDs
|
||||
*
|
||||
* @see com.google.common.collect.BiMap
|
||||
*/
|
||||
private final static BiMap<StringWrapper, UUID> uuidMap = HashBiMap.create(new HashMap<StringWrapper, UUID>());
|
||||
public static boolean CACHED = false;
|
||||
public static UUIDWrapper uuidWrapper = null;
|
||||
public static HashMap<String, PlotPlayer> players = new HashMap<>();
|
||||
|
||||
public static void add(final StringWrapper name, final UUID uuid) {
|
||||
if ((uuid == null) || (name == null)) {
|
||||
return;
|
||||
}
|
||||
BiMap<UUID, StringWrapper> inverse = uuidMap.inverse();
|
||||
if (inverse.containsKey(uuid)) {
|
||||
if (uuidMap.containsKey(name)) {
|
||||
return;
|
||||
}
|
||||
inverse.remove(uuid);
|
||||
}
|
||||
uuidMap.put(name, uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the map containing all names/uuids
|
||||
*
|
||||
* @return map with names + uuids
|
||||
*
|
||||
* @see com.google.common.collect.BiMap
|
||||
*/
|
||||
public static BiMap<StringWrapper, UUID> getUuidMap() {
|
||||
return uuidMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a uuid is cached
|
||||
*
|
||||
* @param uuid to check
|
||||
*
|
||||
* @return true of the uuid is cached
|
||||
*
|
||||
* @see com.google.common.collect.BiMap#containsValue(Object)
|
||||
*/
|
||||
public static boolean uuidExists(final UUID uuid) {
|
||||
return uuidMap.containsValue(uuid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a name is cached
|
||||
*
|
||||
* @param name to check
|
||||
*
|
||||
* @return true of the name is cached
|
||||
*
|
||||
* @see com.google.common.collect.BiMap#containsKey(Object)
|
||||
*/
|
||||
public static boolean nameExists(final StringWrapper name) {
|
||||
return uuidMap.containsKey(name);
|
||||
}
|
||||
|
||||
public static HashSet<UUID> getAllUUIDS() {
|
||||
HashSet<UUID> uuids = new HashSet<UUID>();
|
||||
for (Plot plot : PS.get().getPlotsRaw()) {
|
||||
for (UUID uuid : plot.trusted) {
|
||||
uuids.add(uuid);
|
||||
}
|
||||
for (UUID uuid : plot.members) {
|
||||
uuids.add(uuid);
|
||||
}
|
||||
for (UUID uuid : plot.denied) {
|
||||
uuids.add(uuid);
|
||||
}
|
||||
if (plot.owner != null) {
|
||||
uuids.add(plot.owner);
|
||||
}
|
||||
}
|
||||
return uuids;
|
||||
}
|
||||
|
||||
public static void cacheAll(final String world) {
|
||||
if (CACHED) {
|
||||
return;
|
||||
}
|
||||
final File container = Bukkit.getWorldContainer();
|
||||
UUIDHandler.CACHED = true;
|
||||
TaskManager.runTaskAsync(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
PS.log(C.PREFIX.s() + "&6Starting player data caching for: " + world);
|
||||
final HashMap<StringWrapper, UUID> toAdd = new HashMap<>();
|
||||
toAdd.put(new StringWrapper("*"), DBFunc.everyone);
|
||||
if (Settings.TWIN_MODE_UUID) {
|
||||
HashSet<UUID> all = getAllUUIDS();
|
||||
PS.log("&aFast mode UUID caching enabled!");
|
||||
final File playerdataFolder = new File(container, world + File.separator + "playerdata");
|
||||
String[] dat = playerdataFolder.list(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(final File f, final String s) {
|
||||
return s.endsWith(".dat");
|
||||
}
|
||||
});
|
||||
boolean check = all.size() == 0;
|
||||
if (dat != null) {
|
||||
for (final String current : dat) {
|
||||
final String s = current.replaceAll(".dat$", "");
|
||||
try {
|
||||
UUID uuid = UUID.fromString(s);
|
||||
if (check || all.contains(uuid)) {
|
||||
File file = new File(playerdataFolder + File.separator + current);
|
||||
InputSupplier<FileInputStream> is = Files.newInputStreamSupplier(file);
|
||||
NbtCompound compound = NbtFactory.fromStream(is, StreamOptions.GZIP_COMPRESSION);
|
||||
NbtCompound bukkit = (NbtCompound) compound.get("bukkit");
|
||||
String name = (String) bukkit.get("lastKnownName");
|
||||
long last = (long) bukkit.get("lastPlayed");
|
||||
ExpireManager.dates.put(uuid, last);
|
||||
toAdd.put(new StringWrapper(name), uuid);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
e.printStackTrace();
|
||||
PS.log(C.PREFIX.s() + "Invalid playerdata: " + current);
|
||||
}
|
||||
}
|
||||
}
|
||||
cache(toAdd);
|
||||
return;
|
||||
}
|
||||
final HashSet<String> worlds = new HashSet<>();
|
||||
worlds.add(world);
|
||||
worlds.add("world");
|
||||
final HashSet<UUID> uuids = new HashSet<>();
|
||||
final HashSet<String> names = new HashSet<>();
|
||||
File playerdataFolder = null;
|
||||
for (final String worldname : worlds) {
|
||||
// Getting UUIDs
|
||||
playerdataFolder = new File(container, worldname + File.separator + "playerdata");
|
||||
String[] dat = playerdataFolder.list(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(final File f, final String s) {
|
||||
return s.endsWith(".dat");
|
||||
}
|
||||
});
|
||||
if (dat != null && dat.length != 0) {
|
||||
for (final String current : dat) {
|
||||
final String s = current.replaceAll(".dat$", "");
|
||||
try {
|
||||
final UUID uuid = UUID.fromString(s);
|
||||
uuids.add(uuid);
|
||||
} catch (final Exception e) {
|
||||
PS.log(C.PREFIX.s() + "Invalid playerdata: " + current);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Getting names
|
||||
final File playersFolder = new File(worldname + File.separator + "players");
|
||||
dat = playersFolder.list(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(final File f, final String s) {
|
||||
return s.endsWith(".dat");
|
||||
}
|
||||
});
|
||||
if (dat != null && dat.length != 0) {
|
||||
for (final String current : dat) {
|
||||
names.add(current.replaceAll(".dat$", ""));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (UUID uuid : uuids) {
|
||||
try {
|
||||
File file = new File(playerdataFolder + File.separator + uuid.toString() + ".dat");
|
||||
InputSupplier<FileInputStream> is = Files.newInputStreamSupplier(file);
|
||||
NbtCompound compound = NbtFactory.fromStream(is, StreamOptions.GZIP_COMPRESSION);
|
||||
NbtCompound bukkit = (NbtCompound) compound.get("bukkit");
|
||||
String name = (String) bukkit.get("lastKnownName");
|
||||
long last = (long) bukkit.get("lastPlayed");
|
||||
if (Settings.OFFLINE_MODE) {
|
||||
if (!Settings.UUID_LOWERCASE || !name.toLowerCase().equals(name)) {
|
||||
long most = (long) compound.get("UUIDMost");
|
||||
long least = (long) compound.get("UUIDLeast");
|
||||
uuid = new UUID(most, least);
|
||||
}
|
||||
}
|
||||
ExpireManager.dates.put(uuid, last);
|
||||
toAdd.put(new StringWrapper(name), uuid);
|
||||
} catch (final Throwable e) {
|
||||
PS.log(C.PREFIX.s() + "&6Invalid playerdata: " + uuid.toString() + ".dat");
|
||||
}
|
||||
}
|
||||
for (final String name : names) {
|
||||
final UUID uuid = uuidWrapper.getUUID(name);
|
||||
final StringWrapper nameWrap = new StringWrapper(name);
|
||||
toAdd.put(nameWrap, uuid);
|
||||
}
|
||||
|
||||
if (uuidMap.size() == 0) {
|
||||
for (OfflinePlotPlayer op : uuidWrapper.getOfflinePlayers()) {
|
||||
if (op.getLastPlayed() != 0) {
|
||||
String name = op.getName();
|
||||
StringWrapper wrap = new StringWrapper(name);
|
||||
UUID uuid = uuidWrapper.getUUID(op);
|
||||
toAdd.put(wrap, uuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
cache(toAdd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void cache(final HashMap<StringWrapper, UUID> toAdd) {
|
||||
TaskManager.runTask(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (Entry<StringWrapper, UUID> entry : toAdd.entrySet()) {
|
||||
add(entry.getKey(), entry.getValue());
|
||||
}
|
||||
PS.log(C.PREFIX.s() + "&6Cached a total of: " + UUIDHandler.uuidMap.size() + " UUIDs");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static UUID getUUID(final PlotPlayer player) {
|
||||
return UUIDHandler.uuidWrapper.getUUID(player);
|
||||
}
|
||||
|
||||
public static UUID getUUID(final BukkitOfflinePlayer player) {
|
||||
return UUIDHandler.uuidWrapper.getUUID(player);
|
||||
}
|
||||
|
||||
public static String getName(final UUID uuid) {
|
||||
if (uuid == null) {
|
||||
return null;
|
||||
}
|
||||
// check online
|
||||
final PlotPlayer player = UUIDHandler.getPlayer(uuid);
|
||||
if (player != null) {
|
||||
return player.getName();
|
||||
}
|
||||
// check cache
|
||||
final StringWrapper name = UUIDHandler.uuidMap.inverse().get(uuid);
|
||||
if (name != null) {
|
||||
return name.value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PlotPlayer getPlayer(final UUID uuid) {
|
||||
for (final PlotPlayer player : players.values()) {
|
||||
if (player.getUUID().equals(uuid)) {
|
||||
return player;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PlotPlayer getPlayer(final String name) {
|
||||
return players.get(name);
|
||||
}
|
||||
|
||||
public static UUID getUUID(final String name) {
|
||||
if ((name == null) || (name.length() == 0)) {
|
||||
return null;
|
||||
}
|
||||
// check online
|
||||
final PlotPlayer player = getPlayer(name);
|
||||
if (player != null) {
|
||||
return player.getUUID();
|
||||
}
|
||||
// check cache
|
||||
final StringWrapper wrap = new StringWrapper(name);
|
||||
UUID uuid = UUIDHandler.uuidMap.get(wrap);
|
||||
if (uuid != null) {
|
||||
return uuid;
|
||||
}
|
||||
// Read from disk OR convert directly to offline UUID
|
||||
if (Settings.UUID_FROM_DISK || (uuidWrapper instanceof OfflineUUIDWrapper)) {
|
||||
uuid = UUIDHandler.uuidWrapper.getUUID(name);
|
||||
add(new StringWrapper(name), uuid);
|
||||
return uuid;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit.chat;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
|
||||
/**
|
||||
* Represents a wrapper around an array class of an arbitrary reference type,
|
||||
* which properly implements "value" hash code and equality functions.
|
||||
* <p>
|
||||
* This class is intended for use as a key to a map.
|
||||
* </p>
|
||||
* @author Glen Husman
|
||||
* @param <E> The type of elements in the array.
|
||||
* @see Arrays
|
||||
*/
|
||||
public final class ArrayWrapper<E> {
|
||||
|
||||
/**
|
||||
* Creates an array wrapper with some elements.
|
||||
* @param elements The elements of the array.
|
||||
*/
|
||||
public ArrayWrapper(E... elements){
|
||||
setArray(elements);
|
||||
}
|
||||
|
||||
private E[] _array;
|
||||
|
||||
/**
|
||||
* Retrieves a reference to the wrapped array instance.
|
||||
* @return The array wrapped by this instance.
|
||||
*/
|
||||
public E[] getArray(){
|
||||
return _array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set this wrapper to wrap a new array instance.
|
||||
* @param array The new wrapped array.
|
||||
*/
|
||||
public void setArray(E[] array){
|
||||
Validate.notNull(array, "The array must not be null.");
|
||||
_array = array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this object has a value equivalent to another object.
|
||||
* @see Arrays#equals(Object[], Object[])
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public boolean equals(Object other)
|
||||
{
|
||||
if (!(other instanceof ArrayWrapper))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return Arrays.equals(_array, ((ArrayWrapper)other)._array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the hash code represented by this objects value.
|
||||
* @see Arrays#hashCode(Object[])
|
||||
* @return This object's hash code.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
return Arrays.hashCode(_array);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an iterable element collection to an array of elements.
|
||||
* The iteration order of the specified object will be used as the array element order.
|
||||
* @param list The iterable of objects which will be converted to an array.
|
||||
* @param c The type of the elements of the array.
|
||||
* @return An array of elements in the specified iterable.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T[] toArray(Iterable<? extends T> list, Class<T> c) {
|
||||
int size = -1;
|
||||
if(list instanceof Collection<?>){
|
||||
@SuppressWarnings("rawtypes")
|
||||
Collection coll = (Collection)list;
|
||||
size = coll.size();
|
||||
}
|
||||
|
||||
|
||||
if(size < 0){
|
||||
size = 0;
|
||||
// Ugly hack: Count it ourselves
|
||||
for(@SuppressWarnings("unused") T element : list){
|
||||
size++;
|
||||
}
|
||||
}
|
||||
|
||||
T[] result = (T[]) Array.newInstance(c, size);
|
||||
int i = 0;
|
||||
for(T element : list){ // Assumes iteration order is consistent
|
||||
result[i++] = element; // Assign array element at index THEN increment counter
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
@ -0,0 +1,845 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit.chat;
|
||||
|
||||
import static com.intellectualcrafters.plot.util.bukkit.chat.TextualComponent.rawText;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Achievement;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.Statistic;
|
||||
import org.bukkit.Statistic.Type;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
|
||||
import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
|
||||
|
||||
/**
|
||||
* Represents a formattable message. Such messages can use elements such as colors, formatting codes, hover and click data, and other features provided by the vanilla Minecraft <a href="http://minecraft.gamepedia.com/Tellraw#Raw_JSON_Text">JSON message formatter</a>.
|
||||
* This class allows plugins to emulate the functionality of the vanilla Minecraft <a href="http://minecraft.gamepedia.com/Commands#tellraw">tellraw command</a>.
|
||||
* <p>
|
||||
* This class follows the builder pattern, allowing for method chaining.
|
||||
* It is set up such that invocations of property-setting methods will affect the current editing component,
|
||||
* and a call to {@link #then()} or {@link #then(Object)} will append a new editing component to the end of the message,
|
||||
* optionally initializing it with text. Further property-setting method calls will affect that editing component.
|
||||
* </p>
|
||||
*/
|
||||
public class FancyMessage implements JsonRepresentedObject, Cloneable, Iterable<MessagePart>, ConfigurationSerializable {
|
||||
|
||||
static{
|
||||
ConfigurationSerialization.registerClass(FancyMessage.class);
|
||||
}
|
||||
|
||||
private List<MessagePart> messageParts;
|
||||
private String jsonString;
|
||||
private boolean dirty;
|
||||
|
||||
private static Constructor<?> nmsPacketPlayOutChatConstructor;
|
||||
|
||||
@Override
|
||||
public FancyMessage clone() throws CloneNotSupportedException{
|
||||
FancyMessage instance = (FancyMessage)super.clone();
|
||||
instance.messageParts = new ArrayList<MessagePart>(messageParts.size());
|
||||
for(int i = 0; i < messageParts.size(); i++){
|
||||
instance.messageParts.add(i, messageParts.get(i).clone());
|
||||
}
|
||||
instance.dirty = false;
|
||||
instance.jsonString = null;
|
||||
return instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON message with text.
|
||||
* @param firstPartText The existing text in the message.
|
||||
*/
|
||||
public FancyMessage(final String firstPartText) {
|
||||
this(rawText(firstPartText));
|
||||
}
|
||||
|
||||
public FancyMessage(final TextualComponent firstPartText) {
|
||||
messageParts = new ArrayList<MessagePart>();
|
||||
messageParts.add(new MessagePart(firstPartText));
|
||||
jsonString = null;
|
||||
dirty = false;
|
||||
|
||||
if(nmsPacketPlayOutChatConstructor == null){
|
||||
try {
|
||||
nmsPacketPlayOutChatConstructor = Reflection.getNMSClass("PacketPlayOutChat").getDeclaredConstructor(Reflection.getNMSClass("IChatBaseComponent"));
|
||||
nmsPacketPlayOutChatConstructor.setAccessible(true);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Could not find Minecraft method or constructor.", e);
|
||||
} catch (SecurityException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access constructor.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JSON message without text.
|
||||
*/
|
||||
public FancyMessage() {
|
||||
this((TextualComponent)null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of the current editing component to a value.
|
||||
* @param text The new text of the current editing component.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage text(String text) {
|
||||
MessagePart latest = latest();
|
||||
latest.text = rawText(text);
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the text of the current editing component to a value.
|
||||
* @param text The new text of the current editing component.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage text(TextualComponent text) {
|
||||
MessagePart latest = latest();
|
||||
latest.text = text;
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the current editing component to a value.
|
||||
* @param color The new color of the current editing component.
|
||||
* @return This builder instance.
|
||||
* @exception IllegalArgumentException If the specified {@code ChatColor} enumeration value is not a color (but a format value).
|
||||
*/
|
||||
public FancyMessage color(final ChatColor color) {
|
||||
if (!color.isColor()) {
|
||||
throw new IllegalArgumentException(color.name() + " is not a color");
|
||||
}
|
||||
latest().color = color;
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the stylization of the current editing component.
|
||||
* @param styles The array of styles to apply to the editing component.
|
||||
* @return This builder instance.
|
||||
* @exception IllegalArgumentException If any of the enumeration values in the array do not represent formatters.
|
||||
*/
|
||||
public FancyMessage style(ChatColor... styles) {
|
||||
for (final ChatColor style : styles) {
|
||||
if (!style.isFormat()) {
|
||||
throw new IllegalArgumentException(style.name() + " is not a style");
|
||||
}
|
||||
}
|
||||
latest().styles.addAll(Arrays.asList(styles));
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to instruct the client to open a file on the client side filesystem when the currently edited part of the {@code FancyMessage} is clicked.
|
||||
* @param path The path of the file on the client filesystem.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage file(final String path) {
|
||||
onClick("open_file", path);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to instruct the client to open a webpage in the client's web browser when the currently edited part of the {@code FancyMessage} is clicked.
|
||||
* @param url The URL of the page to open when the link is clicked.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage link(final String url) {
|
||||
onClick("open_url", url);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to instruct the client to replace the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is clicked.
|
||||
* The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key.
|
||||
* @param command The text to display in the chat bar of the client.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage suggest(final String command) {
|
||||
onClick("suggest_command", command);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to instruct the client to append the chat input box content with the specified string when the currently edited part of the {@code FancyMessage} is SHIFT-CLICKED.
|
||||
* The client will not immediately send the command to the server to be executed unless the client player submits the command/chat message, usually with the enter key.
|
||||
* @param command The text to append to the chat bar of the client.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage insert(final String command) {
|
||||
latest().insertionData = command;
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to instruct the client to send the specified string to the server as a chat message when the currently edited part of the {@code FancyMessage} is clicked.
|
||||
* The client <b>will</b> immediately send the command to the server to be executed when the editing component is clicked.
|
||||
* @param command The text to display in the chat bar of the client.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage command(final String command) {
|
||||
onClick("run_command", command);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display information about an achievement when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param name The name of the achievement to display, excluding the "achievement." prefix.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage achievementTooltip(final String name) {
|
||||
onHover("show_achievement", new JsonString("achievement." + name));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display information about an achievement when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param which The achievement to display.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage achievementTooltip(final Achievement which) {
|
||||
try {
|
||||
Object achievement = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSAchievement", Achievement.class).invoke(null, which);
|
||||
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Achievement"), "name").get(achievement));
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
return this;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
return this;
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display information about a parameterless statistic when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param which The statistic to display.
|
||||
* @return This builder instance.
|
||||
* @exception IllegalArgumentException If the statistic requires a parameter which was not supplied.
|
||||
*/
|
||||
public FancyMessage statisticTooltip(final Statistic which) {
|
||||
Type type = which.getType();
|
||||
if (type != Type.UNTYPED) {
|
||||
throw new IllegalArgumentException("That statistic requires an additional " + type + " parameter!");
|
||||
}
|
||||
try {
|
||||
Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getNMSStatistic", Statistic.class).invoke(null, which);
|
||||
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
return this;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
return this;
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display information about a statistic parameter with a material when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param which The statistic to display.
|
||||
* @param item The sole material parameter to the statistic.
|
||||
* @return This builder instance.
|
||||
* @exception IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required.
|
||||
*/
|
||||
public FancyMessage statisticTooltip(final Statistic which, Material item) {
|
||||
Type type = which.getType();
|
||||
if (type == Type.UNTYPED) {
|
||||
throw new IllegalArgumentException("That statistic needs no additional parameter!");
|
||||
}
|
||||
if ((type == Type.BLOCK && item.isBlock()) || type == Type.ENTITY) {
|
||||
throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!");
|
||||
}
|
||||
try {
|
||||
Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getMaterialStatistic", Statistic.class, Material.class).invoke(null, which, item);
|
||||
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
return this;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
return this;
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display information about a statistic parameter with an entity type when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param which The statistic to display.
|
||||
* @param entity The sole entity type parameter to the statistic.
|
||||
* @return This builder instance.
|
||||
* @exception IllegalArgumentException If the statistic requires a parameter which was not supplied, or was supplied a parameter that was not required.
|
||||
*/
|
||||
public FancyMessage statisticTooltip(final Statistic which, EntityType entity) {
|
||||
Type type = which.getType();
|
||||
if (type == Type.UNTYPED) {
|
||||
throw new IllegalArgumentException("That statistic needs no additional parameter!");
|
||||
}
|
||||
if (type != Type.ENTITY) {
|
||||
throw new IllegalArgumentException("Wrong parameter type for that statistic - needs " + type + "!");
|
||||
}
|
||||
try {
|
||||
Object statistic = Reflection.getMethod(Reflection.getOBCClass("CraftStatistic"), "getEntityStatistic", Statistic.class, EntityType.class).invoke(null, which, entity);
|
||||
return achievementTooltip((String) Reflection.getField(Reflection.getNMSClass("Statistic"), "name").get(statistic));
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
return this;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
return this;
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display information about an item when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param itemJSON A string representing the JSON-serialized NBT data tag of an {@link ItemStack}.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage itemTooltip(final String itemJSON) {
|
||||
onHover("show_item", new JsonString(itemJSON)); // Seems a bit hacky, considering we have a JSON object as a parameter
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display information about an item when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param itemStack The stack for which to display information.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage itemTooltip(final ItemStack itemStack) {
|
||||
try {
|
||||
Object nmsItem = Reflection.getMethod(Reflection.getOBCClass("inventory.CraftItemStack"), "asNMSCopy", ItemStack.class).invoke(null, itemStack);
|
||||
return itemTooltip(Reflection.getMethod(Reflection.getNMSClass("ItemStack"), "save", Reflection.getNMSClass("NBTTagCompound")).invoke(nmsItem, Reflection.getNMSClass("NBTTagCompound").newInstance()).toString());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display raw text when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param text The text, which supports newlines, which will be displayed to the client upon hovering.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage tooltip(final String text) {
|
||||
onHover("show_text", new JsonString(text));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display raw text when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage tooltip(final Iterable<String> lines) {
|
||||
tooltip(ArrayWrapper.toArray(lines, String.class));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display raw text when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param lines The lines of text which will be displayed to the client upon hovering.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage tooltip(final String... lines) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for(int i = 0; i < lines.length; i++){
|
||||
builder.append(lines[i]);
|
||||
if(i != lines.length - 1){
|
||||
builder.append('\n');
|
||||
}
|
||||
}
|
||||
tooltip(builder.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display formatted text when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param text The formatted text which will be displayed to the client upon hovering.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage formattedTooltip(FancyMessage text){
|
||||
for(MessagePart component : text.messageParts){
|
||||
if(component.clickActionData != null && component.clickActionName != null){
|
||||
throw new IllegalArgumentException("The tooltip text cannot have click data.");
|
||||
}else if(component.hoverActionData != null && component.hoverActionName != null){
|
||||
throw new IllegalArgumentException("The tooltip text cannot have a tooltip.");
|
||||
}
|
||||
}
|
||||
onHover("show_text", text);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param lines The lines of formatted text which will be displayed to the client upon hovering.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage formattedTooltip(FancyMessage... lines){
|
||||
if(lines.length < 1){
|
||||
onHover(null, null); // Clear tooltip
|
||||
return this;
|
||||
}
|
||||
|
||||
FancyMessage result = new FancyMessage();
|
||||
result.messageParts.clear(); // Remove the one existing text component that exists by default, which destabilizes the object
|
||||
|
||||
for(int i = 0; i < lines.length; i++){
|
||||
try{
|
||||
for(MessagePart component : lines[i]){
|
||||
if(component.clickActionData != null && component.clickActionName != null){
|
||||
throw new IllegalArgumentException("The tooltip text cannot have click data.");
|
||||
}else if(component.hoverActionData != null && component.hoverActionName != null){
|
||||
throw new IllegalArgumentException("The tooltip text cannot have a tooltip.");
|
||||
}
|
||||
if(component.hasText()){
|
||||
result.messageParts.add(component.clone());
|
||||
}
|
||||
}
|
||||
if(i != lines.length - 1){
|
||||
result.messageParts.add(new MessagePart(rawText("\n")));
|
||||
}
|
||||
} catch (CloneNotSupportedException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Failed to clone object", e);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
return formattedTooltip(result.messageParts.isEmpty() ? null : result); // Throws NPE if size is 0, intended
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the behavior of the current editing component to display the specified lines of formatted text when the client hovers over the text.
|
||||
* <p>Tooltips do not inherit display characteristics, such as color and styles, from the message component on which they are applied.</p>
|
||||
* @param lines The lines of text which will be displayed to the client upon hovering. The iteration order of this object will be the order in which the lines of the tooltip are created.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage formattedTooltip(final Iterable<FancyMessage> lines){
|
||||
return formattedTooltip(ArrayWrapper.toArray(lines, FancyMessage.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
|
||||
* @param replacements The replacements, in order, that will be used in the language-specific message.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage translationReplacements(final String... replacements){
|
||||
for(String str : replacements){
|
||||
latest().translationReplacements.add(new JsonString(str));
|
||||
}
|
||||
dirty = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
/*
|
||||
|
||||
/**
|
||||
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
|
||||
* @param replacements The replacements, in order, that will be used in the language-specific message.
|
||||
* @return This builder instance.
|
||||
*/ /* ------------
|
||||
public FancyMessage translationReplacements(final Iterable<? extends CharSequence> replacements){
|
||||
for(CharSequence str : replacements){
|
||||
latest().translationReplacements.add(new JsonString(str));
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
|
||||
* @param replacements The replacements, in order, that will be used in the language-specific message.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage translationReplacements(final FancyMessage... replacements){
|
||||
for(FancyMessage str : replacements){
|
||||
latest().translationReplacements.add(str);
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the text is a translatable key, and it has replaceable values, this function can be used to set the replacements that will be used in the message.
|
||||
* @param replacements The replacements, in order, that will be used in the language-specific message.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage translationReplacements(final Iterable<FancyMessage> replacements){
|
||||
return translationReplacements(ArrayWrapper.toArray(replacements, FancyMessage.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate construction of the current editing component, and begin construction of a new message component.
|
||||
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method.
|
||||
* @param text The text which will populate the new message component.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage then(final String text) {
|
||||
return then(rawText(text));
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate construction of the current editing component, and begin construction of a new message component.
|
||||
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method.
|
||||
* @param text The text which will populate the new message component.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage then(final TextualComponent text) {
|
||||
if (!latest().hasText()) {
|
||||
throw new IllegalStateException("previous message part has no text");
|
||||
}
|
||||
messageParts.add(new MessagePart(text));
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate construction of the current editing component, and begin construction of a new message component.
|
||||
* After a successful call to this method, all setter methods will refer to a new message component, created as a result of the call to this method.
|
||||
* @return This builder instance.
|
||||
*/
|
||||
public FancyMessage then() {
|
||||
if (!latest().hasText()) {
|
||||
throw new IllegalStateException("previous message part has no text");
|
||||
}
|
||||
messageParts.add(new MessagePart());
|
||||
dirty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException{
|
||||
if (messageParts.size() == 1) {
|
||||
latest().writeJson(writer);
|
||||
} else {
|
||||
writer.beginObject().name("text").value("").name("extra").beginArray();
|
||||
for (final MessagePart part : this) {
|
||||
part.writeJson(writer);
|
||||
}
|
||||
writer.endArray().endObject();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize this fancy message, converting it into syntactically-valid JSON using a {@link JsonWriter}.
|
||||
* This JSON should be compatible with vanilla formatter commands such as {@code /tellraw}.
|
||||
* @return The JSON string representing this object.
|
||||
*/
|
||||
public String toJSONString() {
|
||||
if (!dirty && jsonString != null) {
|
||||
return jsonString;
|
||||
}
|
||||
StringWriter string = new StringWriter();
|
||||
JsonWriter json = new JsonWriter(string);
|
||||
try {
|
||||
writeJson(json);
|
||||
json.close();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("invalid message");
|
||||
}
|
||||
jsonString = string.toString();
|
||||
dirty = false;
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this message to a player. The player will receive the fully-fledged formatted display of this message.
|
||||
* @param player The player who will receive the message.
|
||||
*/
|
||||
public void send(Player player){
|
||||
send(player, toJSONString());
|
||||
}
|
||||
|
||||
private void send(CommandSender sender, String jsonString){
|
||||
if (!(sender instanceof Player)){
|
||||
sender.sendMessage(toOldMessageFormat());
|
||||
return;
|
||||
}
|
||||
Player player = (Player) sender;
|
||||
try {
|
||||
Object handle = Reflection.getHandle(player);
|
||||
Object connection = Reflection.getField(handle.getClass(), "playerConnection").get(handle);
|
||||
Reflection.getMethod(connection.getClass(), "sendPacket", Reflection.getNMSClass("Packet")).invoke(connection, createChatPacket(jsonString));
|
||||
} catch (IllegalArgumentException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Argument could not be passed.", e);
|
||||
} catch (IllegalAccessException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not access method.", e);
|
||||
} catch (InstantiationException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Underlying class is abstract.", e);
|
||||
} catch (InvocationTargetException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "A error has occured durring invoking of method.", e);
|
||||
} catch (NoSuchMethodException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not find method.", e);
|
||||
} catch (ClassNotFoundException e) {
|
||||
Bukkit.getLogger().log(Level.WARNING, "Could not find class.", e);
|
||||
}
|
||||
}
|
||||
|
||||
// The ChatSerializer's instance of Gson
|
||||
private static Object nmsChatSerializerGsonInstance;
|
||||
private static Method fromJsonMethod;
|
||||
|
||||
private Object createChatPacket(String json) throws IllegalArgumentException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException, ClassNotFoundException {
|
||||
if(nmsChatSerializerGsonInstance == null){
|
||||
// Find the field and its value, completely bypassing obfuscation
|
||||
Class<?> chatSerializerClazz;
|
||||
|
||||
String version = Reflection.getVersion();
|
||||
double majorVersion = Double.parseDouble(version.replace('_', '.').substring(1, 4));
|
||||
int lesserVersion = Integer.parseInt(version.substring(6, 7));
|
||||
|
||||
if (majorVersion < 1.8 || (majorVersion == 1.8 && lesserVersion == 1)) {
|
||||
chatSerializerClazz = Reflection.getNMSClass("ChatSerializer");
|
||||
} else {
|
||||
chatSerializerClazz = Reflection.getNMSClass("IChatBaseComponent$ChatSerializer");
|
||||
}
|
||||
|
||||
if (chatSerializerClazz == null) {
|
||||
throw new ClassNotFoundException("Can't find the ChatSerializer class");
|
||||
}
|
||||
|
||||
for (Field declaredField : chatSerializerClazz.getDeclaredFields()) {
|
||||
if (Modifier.isFinal(declaredField.getModifiers()) && Modifier.isStatic(declaredField.getModifiers()) && declaredField.getType().getName().endsWith("Gson")) {
|
||||
// We've found our field
|
||||
declaredField.setAccessible(true);
|
||||
nmsChatSerializerGsonInstance = declaredField.get(null);
|
||||
fromJsonMethod = nmsChatSerializerGsonInstance.getClass().getMethod("fromJson", String.class, Class.class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Since the method is so simple, and all the obfuscated methods have the same name, it's easier to reimplement 'IChatBaseComponent a(String)' than to reflectively call it
|
||||
// Of course, the implementation may change, but fuzzy matches might break with signature changes
|
||||
Object serializedChatComponent = fromJsonMethod.invoke(nmsChatSerializerGsonInstance, json, Reflection.getNMSClass("IChatBaseComponent"));
|
||||
|
||||
return nmsPacketPlayOutChatConstructor.newInstance(serializedChatComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this message to a command sender.
|
||||
* If the sender is a player, they will receive the fully-fledged formatted display of this message.
|
||||
* Otherwise, they will receive a version of this message with less formatting.
|
||||
* @param sender The command sender who will receive the message.
|
||||
* @see #toOldMessageFormat()
|
||||
*/
|
||||
public void send(CommandSender sender) {
|
||||
send(sender, toJSONString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends this message to multiple command senders.
|
||||
* @param senders The command senders who will receive the message.
|
||||
* @see #send(CommandSender)
|
||||
*/
|
||||
public void send(final Iterable<? extends CommandSender> senders) {
|
||||
String string = toJSONString();
|
||||
for (final CommandSender sender : senders) {
|
||||
send(sender, string);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert this message to a human-readable string with limited formatting.
|
||||
* This method is used to send this message to clients without JSON formatting support.
|
||||
* <p>
|
||||
* Serialization of this message by using this message will include (in this order for each message part):
|
||||
* <ol>
|
||||
* <li>The color of each message part.</li>
|
||||
* <li>The applicable stylizations for each message part.</li>
|
||||
* <li>The core text of the message part.</li>
|
||||
* </ol>
|
||||
* The primary omissions are tooltips and clickable actions. Consequently, this method should be used only as a last resort.
|
||||
* </p>
|
||||
* <p>
|
||||
* Color and formatting can be removed from the returned string by using {@link ChatColor#stripColor(String)}.</p>
|
||||
* @return A human-readable string representing limited formatting in addition to the core text of this message.
|
||||
*/
|
||||
public String toOldMessageFormat() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
for (MessagePart part : this) {
|
||||
result.append(part.color == null ? "" : part.color);
|
||||
for(ChatColor formatSpecifier : part.styles){
|
||||
result.append(formatSpecifier);
|
||||
}
|
||||
result.append(part.text);
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
private MessagePart latest() {
|
||||
return messageParts.get(messageParts.size() - 1);
|
||||
}
|
||||
|
||||
private void onClick(final String name, final String data) {
|
||||
final MessagePart latest = latest();
|
||||
latest.clickActionName = name;
|
||||
latest.clickActionData = data;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
private void onHover(final String name, final JsonRepresentedObject data) {
|
||||
final MessagePart latest = latest();
|
||||
latest.hoverActionName = name;
|
||||
latest.hoverActionData = data;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
// Doc copied from interface
|
||||
public Map<String, Object> serialize() {
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("messageParts", messageParts);
|
||||
// map.put("JSON", toJSONString());
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a JSON-represented message from a mapping of key-value pairs.
|
||||
* This is called by the Bukkit serialization API.
|
||||
* It is not intended for direct public API consumption.
|
||||
* @param serialized The key-value mapping which represents a fancy message.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static FancyMessage deserialize(Map<String, Object> serialized){
|
||||
FancyMessage msg = new FancyMessage();
|
||||
msg.messageParts = (List<MessagePart>)serialized.get("messageParts");
|
||||
msg.jsonString = serialized.containsKey("JSON") ? serialized.get("JSON").toString() : null;
|
||||
msg.dirty = !serialized.containsKey("JSON");
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* <b>Internally called method. Not for API consumption.</b>
|
||||
*/
|
||||
public Iterator<MessagePart> iterator() {
|
||||
return messageParts.iterator();
|
||||
}
|
||||
|
||||
private static JsonParser _stringParser = new JsonParser();
|
||||
|
||||
/**
|
||||
* Deserializes a fancy message from its JSON representation. This JSON representation is of the format of
|
||||
* that returned by {@link #toJSONString()}, and is compatible with vanilla inputs.
|
||||
* @param json The JSON string which represents a fancy message.
|
||||
* @return A {@code FancyMessage} representing the parameterized JSON message.
|
||||
*/
|
||||
public static FancyMessage deserialize(String json){
|
||||
JsonObject serialized = _stringParser.parse(json).getAsJsonObject();
|
||||
JsonArray extra = serialized.getAsJsonArray("extra"); // Get the extra component
|
||||
FancyMessage returnVal = new FancyMessage();
|
||||
returnVal.messageParts.clear();
|
||||
for(JsonElement mPrt : extra){
|
||||
MessagePart component = new MessagePart();
|
||||
JsonObject messagePart = mPrt.getAsJsonObject();
|
||||
for(Map.Entry<String, JsonElement> entry : messagePart.entrySet()){
|
||||
// Deserialize text
|
||||
if(TextualComponent.isTextKey(entry.getKey())){
|
||||
// The map mimics the YAML serialization, which has a "key" field and one or more "value" fields
|
||||
Map<String, Object> serializedMapForm = new HashMap<String, Object>(); // Must be object due to Bukkit serializer API compliance
|
||||
serializedMapForm.put("key", entry.getKey());
|
||||
if(entry.getValue().isJsonPrimitive()){
|
||||
// Assume string
|
||||
serializedMapForm.put("value", entry.getValue().getAsString());
|
||||
}else{
|
||||
// Composite object, but we assume each element is a string
|
||||
for(Map.Entry<String, JsonElement> compositeNestedElement : entry.getValue().getAsJsonObject().entrySet()){
|
||||
serializedMapForm.put("value." + compositeNestedElement.getKey(), compositeNestedElement.getValue().getAsString());
|
||||
}
|
||||
}
|
||||
component.text = TextualComponent.deserialize(serializedMapForm);
|
||||
}else if(MessagePart.stylesToNames.inverse().containsKey(entry.getKey())){
|
||||
if(entry.getValue().getAsBoolean()){
|
||||
component.styles.add(MessagePart.stylesToNames.inverse().get(entry.getKey()));
|
||||
}
|
||||
}else if(entry.getKey().equals("color")){
|
||||
component.color = ChatColor.valueOf(entry.getValue().getAsString().toUpperCase());
|
||||
}else if(entry.getKey().equals("clickEvent")){
|
||||
JsonObject object = entry.getValue().getAsJsonObject();
|
||||
component.clickActionName = object.get("action").getAsString();
|
||||
component.clickActionData = object.get("value").getAsString();
|
||||
}else if(entry.getKey().equals("hoverEvent")){
|
||||
JsonObject object = entry.getValue().getAsJsonObject();
|
||||
component.hoverActionName = object.get("action").getAsString();
|
||||
if(object.get("value").isJsonPrimitive()){
|
||||
// Assume string
|
||||
component.hoverActionData = new JsonString(object.get("value").getAsString());
|
||||
}else{
|
||||
// Assume composite type
|
||||
// The only composite type we currently store is another FancyMessage
|
||||
// Therefore, recursion time!
|
||||
component.hoverActionData = deserialize(object.get("value").toString() /* This should properly serialize the JSON object as a JSON string */);
|
||||
}
|
||||
}else if(entry.getKey().equals("insertion")){
|
||||
component.insertionData = entry.getValue().getAsString();
|
||||
}else if(entry.getKey().equals("with")){
|
||||
for(JsonElement object : entry.getValue().getAsJsonArray()){
|
||||
if(object.isJsonPrimitive()){
|
||||
component.translationReplacements.add(new JsonString(object.getAsString()));
|
||||
}else{
|
||||
// Only composite type stored in this array is - again - FancyMessages
|
||||
// Recurse within this function to parse this as a translation replacement
|
||||
component.translationReplacements.add(deserialize(object.toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
returnVal.messageParts.add(component);
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit.chat;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
|
||||
/**
|
||||
* Represents an object that can be serialized to a JSON writer instance.
|
||||
*/
|
||||
interface JsonRepresentedObject {
|
||||
|
||||
/**
|
||||
* Writes the JSON representation of this object to the specified writer.
|
||||
* @param writer The JSON writer which will receive the object.
|
||||
* @throws IOException If an error occurs writing to the stream.
|
||||
*/
|
||||
public void writeJson(JsonWriter writer) throws IOException;
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit.chat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
|
||||
|
||||
/**
|
||||
* Represents a JSON string value.
|
||||
* Writes by this object will not write name values nor begin/end objects in the JSON stream.
|
||||
* All writes merely write the represented string value.
|
||||
*/
|
||||
final class JsonString implements JsonRepresentedObject, ConfigurationSerializable {
|
||||
|
||||
private String _value;
|
||||
|
||||
public JsonString(CharSequence value){
|
||||
_value = value == null ? null : value.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
writer.value(getValue());
|
||||
}
|
||||
|
||||
public String getValue(){
|
||||
return _value;
|
||||
}
|
||||
|
||||
public Map<String, Object> serialize() {
|
||||
HashMap<String, Object> theSingleValue = new HashMap<String, Object>();
|
||||
theSingleValue.put("stringValue", _value);
|
||||
return theSingleValue;
|
||||
}
|
||||
|
||||
public static JsonString deserialize(Map<String, Object> map){
|
||||
return new JsonString(map.get("stringValue").toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(){
|
||||
return _value;
|
||||
}
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit.chat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
import com.google.common.collect.BiMap;
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
|
||||
import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
|
||||
|
||||
/**
|
||||
* Internal class: Represents a component of a JSON-serializable {@link FancyMessage}.
|
||||
*/
|
||||
final class MessagePart implements JsonRepresentedObject, ConfigurationSerializable, Cloneable {
|
||||
|
||||
ChatColor color = ChatColor.WHITE;
|
||||
ArrayList<ChatColor> styles = new ArrayList<ChatColor>();
|
||||
String clickActionName = null, clickActionData = null,
|
||||
hoverActionName = null;
|
||||
JsonRepresentedObject hoverActionData = null;
|
||||
TextualComponent text = null;
|
||||
String insertionData = null;
|
||||
ArrayList<JsonRepresentedObject> translationReplacements = new ArrayList<JsonRepresentedObject>();
|
||||
|
||||
MessagePart(final TextualComponent text){
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
MessagePart() {
|
||||
this.text = null;
|
||||
}
|
||||
|
||||
boolean hasText() {
|
||||
return text != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public MessagePart clone() throws CloneNotSupportedException{
|
||||
MessagePart obj = (MessagePart)super.clone();
|
||||
obj.styles = (ArrayList<ChatColor>)styles.clone();
|
||||
if(hoverActionData instanceof JsonString){
|
||||
obj.hoverActionData = new JsonString(((JsonString)hoverActionData).getValue());
|
||||
}else if(hoverActionData instanceof FancyMessage){
|
||||
obj.hoverActionData = ((FancyMessage)hoverActionData).clone();
|
||||
}
|
||||
obj.translationReplacements = (ArrayList<JsonRepresentedObject>)translationReplacements.clone();
|
||||
return obj;
|
||||
|
||||
}
|
||||
|
||||
static final BiMap<ChatColor, String> stylesToNames;
|
||||
|
||||
static{
|
||||
ImmutableBiMap.Builder<ChatColor, String> builder = ImmutableBiMap.builder();
|
||||
for (final ChatColor style : ChatColor.values()){
|
||||
if(!style.isFormat()){
|
||||
continue;
|
||||
}
|
||||
|
||||
String styleName;
|
||||
switch (style) {
|
||||
case MAGIC:
|
||||
styleName = "obfuscated"; break;
|
||||
case UNDERLINE:
|
||||
styleName = "underlined"; break;
|
||||
default:
|
||||
styleName = style.name().toLowerCase(); break;
|
||||
}
|
||||
|
||||
builder.put(style, styleName);
|
||||
}
|
||||
stylesToNames = builder.build();
|
||||
}
|
||||
|
||||
public void writeJson(JsonWriter json) {
|
||||
try {
|
||||
json.beginObject();
|
||||
text.writeJson(json);
|
||||
json.name("color").value(color.name().toLowerCase());
|
||||
for (final ChatColor style : styles) {
|
||||
json.name(stylesToNames.get(style)).value(true);
|
||||
}
|
||||
if (clickActionName != null && clickActionData != null) {
|
||||
json.name("clickEvent")
|
||||
.beginObject()
|
||||
.name("action").value(clickActionName)
|
||||
.name("value").value(clickActionData)
|
||||
.endObject();
|
||||
}
|
||||
if (hoverActionName != null && hoverActionData != null) {
|
||||
json.name("hoverEvent")
|
||||
.beginObject()
|
||||
.name("action").value(hoverActionName)
|
||||
.name("value");
|
||||
hoverActionData.writeJson(json);
|
||||
json.endObject();
|
||||
}
|
||||
if(insertionData != null){
|
||||
json.name("insertion").value(insertionData);
|
||||
}
|
||||
if(translationReplacements.size() > 0 && text != null && TextualComponent.isTranslatableText(text)){
|
||||
json.name("with").beginArray();
|
||||
for(JsonRepresentedObject obj : translationReplacements){
|
||||
obj.writeJson(json);
|
||||
}
|
||||
json.endArray();
|
||||
}
|
||||
json.endObject();
|
||||
} catch(IOException e){
|
||||
Bukkit.getLogger().log(Level.WARNING, "A problem occured during writing of JSON string", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> serialize() {
|
||||
HashMap<String, Object> map = new HashMap<String, Object>();
|
||||
map.put("text", text);
|
||||
map.put("styles", styles);
|
||||
map.put("color", color.getChar());
|
||||
map.put("hoverActionName", hoverActionName);
|
||||
map.put("hoverActionData", hoverActionData);
|
||||
map.put("clickActionName", clickActionName);
|
||||
map.put("clickActionData", clickActionData);
|
||||
map.put("insertion", insertionData);
|
||||
map.put("translationReplacements", translationReplacements);
|
||||
return map;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static MessagePart deserialize(Map<String, Object> serialized){
|
||||
MessagePart part = new MessagePart((TextualComponent)serialized.get("text"));
|
||||
part.styles = (ArrayList<ChatColor>)serialized.get("styles");
|
||||
part.color = ChatColor.getByChar(serialized.get("color").toString());
|
||||
part.hoverActionName = (String)serialized.get("hoverActionName");
|
||||
part.hoverActionData = (JsonRepresentedObject)serialized.get("hoverActionData");
|
||||
part.clickActionName = (String)serialized.get("clickActionName");
|
||||
part.clickActionData = (String)serialized.get("clickActionData");
|
||||
part.insertionData = (String)serialized.get("insertion");
|
||||
part.translationReplacements = (ArrayList<JsonRepresentedObject>)serialized.get("translationReplacements");
|
||||
return part;
|
||||
}
|
||||
|
||||
static{
|
||||
ConfigurationSerialization.registerClass(MessagePart.class);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,213 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit.chat;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
/**
|
||||
* A class containing static utility methods and caches which are intended as reflective conveniences.
|
||||
* Unless otherwise noted, upon failure methods will return {@code null}.
|
||||
*/
|
||||
public final class Reflection {
|
||||
|
||||
private static String _versionString;
|
||||
|
||||
private Reflection(){
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the version string from the package name of the CraftBukkit server implementation.
|
||||
* This is needed to bypass the JAR package name changing on each update.
|
||||
* @return The version string of the OBC and NMS packages, <em>including the trailing dot</em>.
|
||||
*/
|
||||
public synchronized static String getVersion() {
|
||||
if(_versionString == null){
|
||||
if(Bukkit.getServer() == null){
|
||||
// The server hasn't started, static initializer call?
|
||||
return null;
|
||||
}
|
||||
String name = Bukkit.getServer().getClass().getPackage().getName();
|
||||
_versionString = name.substring(name.lastIndexOf('.') + 1) + ".";
|
||||
}
|
||||
|
||||
return _versionString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores loaded classes from the {@code net.minecraft.server} package.
|
||||
*/
|
||||
private static final Map<String, Class<?>> _loadedNMSClasses = new HashMap<String, Class<?>>();
|
||||
/**
|
||||
* Stores loaded classes from the {@code org.bukkit.craftbukkit} package (and subpackages).
|
||||
*/
|
||||
private static final Map<String, Class<?>> _loadedOBCClasses = new HashMap<String, Class<?>>();
|
||||
|
||||
/**
|
||||
* Gets a {@link Class} object representing a type contained within the {@code net.minecraft.server} versioned package.
|
||||
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
|
||||
* @param className The name of the class, excluding the package, within NMS.
|
||||
* @return The class instance representing the specified NMS class, or {@code null} if it could not be loaded.
|
||||
*/
|
||||
public synchronized static Class<?> getNMSClass(String className) {
|
||||
if(_loadedNMSClasses.containsKey(className)){
|
||||
return _loadedNMSClasses.get(className);
|
||||
}
|
||||
|
||||
String fullName = "net.minecraft.server." + getVersion() + className;
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = Class.forName(fullName);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
_loadedNMSClasses.put(className, null);
|
||||
return null;
|
||||
}
|
||||
_loadedNMSClasses.put(className, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a {@link Class} object representing a type contained within the {@code org.bukkit.craftbukkit} versioned package.
|
||||
* The class instances returned by this method are cached, such that no lookup will be done twice (unless multiple threads are accessing this method simultaneously).
|
||||
* @param className The name of the class, excluding the package, within OBC. This name may contain a subpackage name, such as {@code inventory.CraftItemStack}.
|
||||
* @return The class instance representing the specified OBC class, or {@code null} if it could not be loaded.
|
||||
*/
|
||||
public synchronized static Class<?> getOBCClass(String className) {
|
||||
if(_loadedOBCClasses.containsKey(className)){
|
||||
return _loadedOBCClasses.get(className);
|
||||
}
|
||||
|
||||
String fullName = "org.bukkit.craftbukkit." + getVersion() + className;
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = Class.forName(fullName);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
_loadedOBCClasses.put(className, null);
|
||||
return null;
|
||||
}
|
||||
_loadedOBCClasses.put(className, clazz);
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get the NMS handle of a CraftBukkit object.
|
||||
* <p>
|
||||
* The only match currently attempted by this method is a retrieval by using a parameterless {@code getHandle()} method implemented by the runtime type of the specified object.
|
||||
* </p>
|
||||
* @param obj The object for which to retrieve an NMS handle.
|
||||
* @return The NMS handle of the specified object, or {@code null} if it could not be retrieved using {@code getHandle()}.
|
||||
*/
|
||||
public synchronized static Object getHandle(Object obj) {
|
||||
try {
|
||||
return getMethod(obj.getClass(), "getHandle").invoke(obj);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static final Map<Class<?>, Map<String, Field>> _loadedFields = new HashMap<Class<?>, Map<String, Field>>();
|
||||
|
||||
/**
|
||||
* Retrieves a {@link Field} instance declared by the specified class with the specified name.
|
||||
* Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field
|
||||
* returned will be an instance or static field.
|
||||
* <p>
|
||||
* A global caching mechanism within this class is used to store fields. Combined with synchronization, this guarantees that
|
||||
* no field will be reflectively looked up twice.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a field is deemed suitable for return, {@link Field#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
|
||||
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
|
||||
* </p>
|
||||
* @param clazz The class which contains the field to retrieve.
|
||||
* @param name The declared name of the field in the class.
|
||||
* @return A field object with the specified name declared by the specified class.
|
||||
* @see Class#getDeclaredField(String)
|
||||
*/
|
||||
public synchronized static Field getField(Class<?> clazz, String name) {
|
||||
Map<String, Field> loaded;
|
||||
if(!_loadedFields.containsKey(clazz)){
|
||||
loaded = new HashMap<String, Field>();
|
||||
_loadedFields.put(clazz, loaded);
|
||||
}else{
|
||||
loaded = _loadedFields.get(clazz);
|
||||
}
|
||||
if(loaded.containsKey(name)){
|
||||
// If the field is loaded (or cached as not existing), return the relevant value, which might be null
|
||||
return loaded.get(name);
|
||||
}
|
||||
try {
|
||||
Field field = clazz.getDeclaredField(name);
|
||||
field.setAccessible(true);
|
||||
loaded.put(name, field);
|
||||
return field;
|
||||
} catch (Exception e) {
|
||||
// Error loading
|
||||
e.printStackTrace();
|
||||
// Cache field as not existing
|
||||
loaded.put(name, null);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Contains loaded methods in a cache.
|
||||
* The map maps [types to maps of [method names to maps of [parameter types to method instances]]].
|
||||
*/
|
||||
private static final Map<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>> _loadedMethods = new HashMap<Class<?>, Map<String, Map<ArrayWrapper<Class<?>>, Method>>>();
|
||||
|
||||
/**
|
||||
* Retrieves a {@link Method} instance declared by the specified class with the specified name and argument types.
|
||||
* Java access modifiers are ignored during this retrieval. No guarantee is made as to whether the field
|
||||
* returned will be an instance or static field.
|
||||
* <p>
|
||||
* A global caching mechanism within this class is used to store method. Combined with synchronization, this guarantees that
|
||||
* no method will be reflectively looked up twice.
|
||||
* </p>
|
||||
* <p>
|
||||
* If a method is deemed suitable for return, {@link Method#setAccessible(boolean) setAccessible} will be invoked with an argument of {@code true} before it is returned.
|
||||
* This ensures that callers do not have to check or worry about Java access modifiers when dealing with the returned instance.
|
||||
* </p>
|
||||
* <p>
|
||||
* This method does <em>not</em> search superclasses of the specified type for methods with the specified signature.
|
||||
* Callers wishing this behavior should use {@link Class#getDeclaredMethod(String, Class...)}.
|
||||
* @param clazz The class which contains the method to retrieve.
|
||||
* @param name The declared name of the method in the class.
|
||||
* @param args The formal argument types of the method.
|
||||
* @return A method object with the specified name declared by the specified class.
|
||||
*/
|
||||
public synchronized static Method getMethod(Class<?> clazz, String name,
|
||||
Class<?>... args) {
|
||||
if(!_loadedMethods.containsKey(clazz)){
|
||||
_loadedMethods.put(clazz, new HashMap<String, Map<ArrayWrapper<Class<?>>, Method>>());
|
||||
}
|
||||
|
||||
Map<String, Map<ArrayWrapper<Class<?>>, Method>> loadedMethodNames = _loadedMethods.get(clazz);
|
||||
if(!loadedMethodNames.containsKey(name)){
|
||||
loadedMethodNames.put(name, new HashMap<ArrayWrapper<Class<?>>, Method>());
|
||||
}
|
||||
|
||||
Map<ArrayWrapper<Class<?>>, Method> loadedSignatures = loadedMethodNames.get(name);
|
||||
ArrayWrapper<Class<?>> wrappedArg = new ArrayWrapper<Class<?>>(args);
|
||||
if(loadedSignatures.containsKey(wrappedArg)){
|
||||
return loadedSignatures.get(wrappedArg);
|
||||
}
|
||||
|
||||
for (Method m : clazz.getMethods())
|
||||
if (m.getName().equals(name) && Arrays.equals(args, m.getParameterTypes())) {
|
||||
m.setAccessible(true);
|
||||
loadedSignatures.put(wrappedArg, m);
|
||||
return m;
|
||||
}
|
||||
loadedSignatures.put(wrappedArg, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,291 @@
|
||||
package com.intellectualcrafters.plot.util.bukkit.chat;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.stream.JsonWriter;
|
||||
import com.intellectualcrafters.configuration.serialization.ConfigurationSerializable;
|
||||
import com.intellectualcrafters.configuration.serialization.ConfigurationSerialization;
|
||||
|
||||
/**
|
||||
* Represents a textual component of a message part.
|
||||
* This can be used to not only represent string literals in a JSON message,
|
||||
* but also to represent localized strings and other text values.
|
||||
* <p>Different instances of this class can be created with static constructor methods.</p>
|
||||
*/
|
||||
public abstract class TextualComponent implements Cloneable {
|
||||
|
||||
static{
|
||||
ConfigurationSerialization.registerClass(TextualComponent.ArbitraryTextTypeComponent.class);
|
||||
ConfigurationSerialization.registerClass(TextualComponent.ComplexTextTypeComponent.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getReadableString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The JSON key used to represent text components of this type.
|
||||
*/
|
||||
public abstract String getKey();
|
||||
|
||||
/**
|
||||
* @return A readable String
|
||||
*/
|
||||
public abstract String getReadableString();
|
||||
|
||||
/**
|
||||
* Clones a textual component instance.
|
||||
* The returned object should not reference this textual component instance, but should maintain the same key and value.
|
||||
*/
|
||||
@Override
|
||||
public abstract TextualComponent clone() throws CloneNotSupportedException;
|
||||
|
||||
/**
|
||||
* Writes the text data represented by this textual component to the specified JSON writer object.
|
||||
* A new object within the writer is not started.
|
||||
* @param writer The object to which to write the JSON data.
|
||||
* @throws IOException If an error occurs while writing to the stream.
|
||||
*/
|
||||
public abstract void writeJson(JsonWriter writer) throws IOException;
|
||||
|
||||
static TextualComponent deserialize(Map<String, Object> map){
|
||||
if(map.containsKey("key") && map.size() == 2 && map.containsKey("value")){
|
||||
// Arbitrary text component
|
||||
return ArbitraryTextTypeComponent.deserialize(map);
|
||||
}else if(map.size() >= 2 && map.containsKey("key") && !map.containsKey("value") /* It contains keys that START WITH value */){
|
||||
// Complex JSON object
|
||||
return ComplexTextTypeComponent.deserialize(map);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
static boolean isTextKey(String key){
|
||||
return key.equals("translate") || key.equals("text") || key.equals("score") || key.equals("selector");
|
||||
}
|
||||
|
||||
static boolean isTranslatableText(TextualComponent component){
|
||||
return component instanceof ComplexTextTypeComponent && ((ComplexTextTypeComponent)component).getKey().equals("translate");
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class used to represent all types of text components.
|
||||
* Exception validating done is on keys and values.
|
||||
*/
|
||||
private static final class ArbitraryTextTypeComponent extends TextualComponent implements ConfigurationSerializable {
|
||||
|
||||
public ArbitraryTextTypeComponent(String key, String value){
|
||||
setKey(key);
|
||||
setValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return _key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
|
||||
_key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
Preconditions.checkArgument(value != null, "The value must be specified.");
|
||||
_value = value;
|
||||
}
|
||||
|
||||
private String _key;
|
||||
private String _value;
|
||||
|
||||
@Override
|
||||
public TextualComponent clone() throws CloneNotSupportedException {
|
||||
// Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone
|
||||
return new ArbitraryTextTypeComponent(getKey(), getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
writer.name(getKey()).value(getValue());
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public Map<String, Object> serialize() {
|
||||
return new HashMap<String, Object>(){{
|
||||
put("key", getKey());
|
||||
put("value", getValue());
|
||||
}};
|
||||
}
|
||||
|
||||
public static ArbitraryTextTypeComponent deserialize(Map<String, Object> map){
|
||||
return new ArbitraryTextTypeComponent(map.get("key").toString(), map.get("value").toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadableString() {
|
||||
return getValue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal class used to represent a text component with a nested JSON value.
|
||||
* Exception validating done is on keys and values.
|
||||
*/
|
||||
private static final class ComplexTextTypeComponent extends TextualComponent implements ConfigurationSerializable{
|
||||
|
||||
public ComplexTextTypeComponent(String key, Map<String, String> values){
|
||||
setKey(key);
|
||||
setValue(values);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKey() {
|
||||
return _key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
Preconditions.checkArgument(key != null && !key.isEmpty(), "The key must be specified.");
|
||||
_key = key;
|
||||
}
|
||||
|
||||
public Map<String, String> getValue() {
|
||||
return _value;
|
||||
}
|
||||
|
||||
public void setValue(Map<String, String> value) {
|
||||
Preconditions.checkArgument(value != null, "The value must be specified.");
|
||||
_value = value;
|
||||
}
|
||||
|
||||
private String _key;
|
||||
private Map<String, String> _value;
|
||||
|
||||
@Override
|
||||
public TextualComponent clone() throws CloneNotSupportedException {
|
||||
// Since this is a private and final class, we can just reinstantiate this class instead of casting super.clone
|
||||
return new ComplexTextTypeComponent(getKey(), getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeJson(JsonWriter writer) throws IOException {
|
||||
writer.name(getKey());
|
||||
writer.beginObject();
|
||||
for(Map.Entry<String, String> jsonPair : _value.entrySet()){
|
||||
writer.name(jsonPair.getKey()).value(jsonPair.getValue());
|
||||
}
|
||||
writer.endObject();
|
||||
}
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public Map<String, Object> serialize() {
|
||||
return new java.util.HashMap<String, Object>(){{
|
||||
put("key", getKey());
|
||||
for(Map.Entry<String, String> valEntry : getValue().entrySet()){
|
||||
put("value." + valEntry.getKey(), valEntry.getValue());
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
||||
public static ComplexTextTypeComponent deserialize(Map<String, Object> map){
|
||||
String key = null;
|
||||
Map<String, String> value = new HashMap<String, String>();
|
||||
for(Map.Entry<String, Object> valEntry : map.entrySet()){
|
||||
if(valEntry.getKey().equals("key")){
|
||||
key = (String) valEntry.getValue();
|
||||
}else if(valEntry.getKey().startsWith("value.")){
|
||||
value.put(((String) valEntry.getKey()).substring(6) /* Strips out the value prefix */, valEntry.getValue().toString());
|
||||
}
|
||||
}
|
||||
return new ComplexTextTypeComponent(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReadableString() {
|
||||
return getKey();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a textual component representing a string literal.
|
||||
* This is the default type of textual component when a single string literal is given to a method.
|
||||
* @param textValue The text which will be represented.
|
||||
* @return The text component representing the specified literal text.
|
||||
*/
|
||||
public static TextualComponent rawText(String textValue){
|
||||
return new ArbitraryTextTypeComponent("text", textValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a textual component representing a localized string.
|
||||
* The client will see this text component as their localized version of the specified string <em>key</em>, which can be overridden by a resource pack.
|
||||
* <p>
|
||||
* If the specified translation key is not present on the client resource pack, the translation key will be displayed as a string literal to the client.
|
||||
* </p>
|
||||
* @param translateKey The string key which maps to localized text.
|
||||
* @return The text component representing the specified localized text.
|
||||
*/
|
||||
public static TextualComponent localizedText(String translateKey){
|
||||
return new ArbitraryTextTypeComponent("translate", translateKey);
|
||||
}
|
||||
|
||||
private static void throwUnsupportedSnapshot(){
|
||||
throw new UnsupportedOperationException("This feature is only supported in snapshot releases.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a textual component representing a scoreboard value.
|
||||
* The client will see their own score for the specified objective as the text represented by this component.
|
||||
* <p>
|
||||
* <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b>
|
||||
* </p>
|
||||
* @param scoreboardObjective The name of the objective for which to display the score.
|
||||
* @return The text component representing the specified scoreboard score (for the viewing player), or {@code null} if an error occurs during JSON serialization.
|
||||
*/
|
||||
public static TextualComponent objectiveScore(String scoreboardObjective){
|
||||
return objectiveScore("*", scoreboardObjective);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a textual component representing a scoreboard value.
|
||||
* The client will see the score of the specified player for the specified objective as the text represented by this component.
|
||||
* <p>
|
||||
* <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b>
|
||||
* </p>
|
||||
* @param playerName The name of the player whos score will be shown. If this string represents the single-character sequence "*", the viewing player's score will be displayed.
|
||||
* Standard minecraft selectors (@a, @p, etc) are <em>not</em> supported.
|
||||
* @param scoreboardObjective The name of the objective for which to display the score.
|
||||
* @return The text component representing the specified scoreboard score for the specified player, or {@code null} if an error occurs during JSON serialization.
|
||||
*/
|
||||
public static TextualComponent objectiveScore(String playerName, String scoreboardObjective){
|
||||
throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE OVERLOADS documentation accordingly
|
||||
|
||||
return new ComplexTextTypeComponent("score", ImmutableMap.<String, String>builder()
|
||||
.put("name", playerName)
|
||||
.put("objective", scoreboardObjective)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a textual component representing a player name, retrievable by using a standard minecraft selector.
|
||||
* The client will see the players or entities captured by the specified selector as the text represented by this component.
|
||||
* <p>
|
||||
* <b>This method is currently guaranteed to throw an {@code UnsupportedOperationException} as it is only supported on snapshot clients.</b>
|
||||
* </p>
|
||||
* @param selector The minecraft player or entity selector which will capture the entities whose string representations will be displayed in the place of this text component.
|
||||
* @return The text component representing the name of the entities captured by the selector.
|
||||
*/
|
||||
public static TextualComponent selector(String selector){
|
||||
throwUnsupportedSnapshot(); // Remove this line when the feature is released to non-snapshot versions, in addition to updating ALL THE OVERLOADS documentation accordingly
|
||||
|
||||
return new ArbitraryTextTypeComponent("selector", selector);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user